source: rtems-tools/linkers/rtems-tld.cpp @ 5025439

4.104.11
Last change on this file since 5025439 was 5025439, checked in by Chris Johns <chrisj@…>, on Sep 21, 2014 at 4:24:37 AM

rtems-tld: Add config options, fix void args, and SCore traces.

  • Property mode set to 100644
File size: 35.4 KB
Line 
1/*
2 * Copyright (c) 2014, 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 <locale>
34#include <sstream>
35
36#include <cxxabi.h>
37#include <signal.h>
38#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
41
42#include <getopt.h>
43
44#include <rld.h>
45#include <rld-cc.h>
46#include <rld-config.h>
47#include <rld-process.h>
48#include <rld-rtems.h>
49
50#ifndef HAVE_KILL
51#define kill(p,s) raise(s)
52#endif
53
54namespace rld
55{
56  /**
57   * RTEMS Trace Linker.
58   */
59  namespace trace
60  {
61    /**
62     * Dump on error user option.
63     */
64    bool dump_on_error;
65
66    /**
67     * A container of arguments.
68     */
69    typedef std::vector < std::string > function_args;
70
71    /**
72     * The return value.
73     */
74    typedef std::string function_return;
75
76    /**
77     * A function's signature.
78     */
79    struct signature
80    {
81      std::string     name; /**< The function's name. */
82      function_args   args; /**< The function's list of arguments. */
83      function_return ret;  /**< The fuctions return value. */
84
85      /**
86       * The default constructor.
87       */
88      signature ();
89
90      /**
91       * Construct the signature loading it from the configuration.
92       */
93      signature (const rld::config::record& record);
94
95      /**
96       * Has the signature got a return value ?
97       */
98      bool has_ret () const;
99
100      /**
101       * Has the signature got any arguments ?
102       */
103      bool has_args () const;
104
105      /**
106       * Return the function's declaration.
107       */
108      const std::string decl (const std::string& prefix = "") const;
109    };
110
111    /**
112     * A container of signatures.
113     */
114    typedef std::map < std::string, signature > signatures;
115
116    /**
117     * A function is list of function signatures headers and defines that allow
118     * a function to be wrapped.
119     */
120    struct function
121    {
122      std::string  name;        /**< The name of this wrapper. */
123      rld::strings headers;     /**< Include statements. */
124      rld::strings defines;     /**< Define statements. */
125      signatures   signatures_; /**< Signatures in this function. */
126
127      /**
128       * Load the function.
129       */
130      function (rld::config::config& config,
131                const std::string&   name);
132
133      /**
134       * Dump the function.
135       */
136      void dump (std::ostream& out) const;
137    };
138
139    /**
140     * A container of functions.
141     */
142    typedef std::vector < function > functions;
143
144    /**
145     * A generator and that contains the functions used to trace arguments and
146     * return values. It also provides the implementation of those functions.
147     */
148    struct generator
149    {
150      std::string  name;            /**< The name of this wrapper. */
151      rld::strings headers;         /**< Include statements. */
152      rld::strings defines;         /**< Define statements. */
153      std::string  entry_trace;     /**< Code template to trace the function entry. */
154      std::string  arg_trace;       /**< Code template to trace an argument. */
155      std::string  exit_trace;      /**< Code template to trace the function exit. */
156      std::string  ret_trace;       /**< Code template to trace the return value. */
157      rld::strings code;            /**< Code block inserted before the trace code. */
158
159      /**
160       * Default constructor.
161       */
162      generator ();
163
164      /**
165       * Load the generator.
166       */
167      generator (rld::config::config& config,
168                 const std::string&   name);
169
170      /**
171       * Dump the generator.
172       */
173      void dump (std::ostream& out) const;
174    };
175
176    /**
177     * Tracer.
178     */
179    class tracer
180    {
181    public:
182      tracer ();
183
184      /**
185       * Load the user's configuration.
186       */
187      void load (rld::config::config& config,
188                 const std::string&   section);
189
190      /**
191       * Process any script based options.
192       */
193      void load_options (const rld::config::section& section);
194
195      /**
196       * The the functions for the trace.
197       */
198      void load_functions (rld::config::config&        config,
199                           const rld::config::section& section);
200
201      /**
202       * The the traces for the tracer.
203       */
204      void load_traces (rld::config::config&        config,
205                        const rld::config::section& section);
206
207      /**
208       * Generate the wrapper object file.
209       */
210      void generate (rld::process::tempfile& c);
211
212      /**
213       * Generate the trace functions.
214       */
215      void generate_traces (rld::process::tempfile& c);
216
217      /**
218       * Get the traces.
219       */
220      const rld::strings& get_traces () const;
221
222      /**
223       * Dump the wrapper.
224       */
225      void dump (std::ostream& out) const;
226
227    private:
228
229      std::string  name;          /**< The name of the trace. */
230      rld::strings traces;        /**< The functions to trace. */
231      functions    functions_;    /**< The functions that can be traced. */
232      generator    generator_;    /**< The tracer's generator. */
233    };
234
235    /**
236     * Trace Linker.
237     */
238    class linker
239    {
240    public:
241      linker ();
242
243      /**
244       * Load the user's configuration.
245       */
246      void load_config (const std::string& path,
247                        const std::string& trace);
248
249      /**
250       * Generate the C file.
251       */
252      void generate_wrapper (rld::process::tempfile& c);
253
254      /**
255       * Compile the C file.
256       */
257      void compile_wrapper (rld::process::tempfile& c,
258                            rld::process::tempfile& o);
259
260      /**
261       * Link the application.
262       */
263      void link (rld::process::tempfile& o,
264                 const std::string&      ld_cmds);
265
266      /**
267       * Dump the linker.
268       */
269      void dump (std::ostream& out) const;
270
271    private:
272
273      rld::config::config    config;     /**< User configuration. */
274      tracer                 tracer_;    /**< The tracer */
275      rld::process::tempfile c; /**< The C wrapper file */
276      rld::process::tempfile o; /**< The wrapper object file */
277    };
278
279    /**
280     * Recursive parser for strings.
281     */
282    void
283    parse (rld::config::config&        config,
284           const rld::config::section& section,
285           const std::string&          sec_name,
286           const std::string&          rec_name,
287           rld::strings&               items,
288           bool                        split = true,
289           int                         depth = 0)
290    {
291      if (depth > 32)
292        throw rld::error ("too deep", "parsing: " + sec_name + '/' + rec_name);
293
294      rld::config::parse_items (section, rec_name, items, false, false, split);
295
296      rld::strings sl;
297
298      rld::config::parse_items (section, sec_name, sl);
299
300      for (rld::strings::iterator sli = sl.begin ();
301           sli != sl.end ();
302           ++sli)
303      {
304        const rld::config::section& sec = config.get_section (*sli);
305        parse (config, sec, sec_name, rec_name, items, split, depth + 1);
306      }
307
308      /*
309       * Make the items unique.
310       */
311      rld::strings::iterator ii;
312      ii = std::unique (items.begin (), items.end ());
313      items.resize (std::distance (items.begin (), ii));
314    }
315
316    signature::signature ()
317    {
318    }
319
320    signature::signature (const rld::config::record& record)
321    {
322      /*
323       * There can only be one function signature in the configuration.
324       */
325      if (!record.single ())
326        throw rld::error ("duplicate", "signature: " + record.name);
327
328      name = record.name;
329
330      /*
331       * Signatures are defined as the return value then the arguments
332       * delimited by a comma and white space. No checking is made of the
333       * return value or arguments.
334       */
335      rld::strings si;
336      rld::config::parse_items (record, si);
337
338      if (si.size () == 0)
339        throw rld::error ("no return value", "signature: " + name);
340      if (si.size () == 1)
341          throw rld::error ("no arguments", "signature: " + name);
342
343      ret = si[0];
344      args.resize (si.size () - 1);
345      std::copy (si.begin ()  + 1, si.end (), args.begin ());
346    }
347
348    bool
349    signature::has_ret () const
350    {
351      /*
352       * @todo Need to define as part of the function signature if ret
353       *       processing is required.
354       */
355      return ret != "void";
356    }
357
358    bool
359    signature::has_args () const
360    {
361      if (args.empty ())
362          return false;
363      return ((args.size() == 1) && (args[0] == "void")) ? false : true;
364    }
365
366    const std::string
367    signature::decl (const std::string& prefix) const
368    {
369      std::string ds = ret + ' ' + prefix + name + '(';
370      if (has_args ())
371      {
372        int arg = 0;
373        for (function_args::const_iterator ai = args.begin ();
374             ai != args.end ();
375             ++ai)
376        {
377          if (ai != args.begin ())
378            ds += ", ";
379          ds += (*ai) + " a" + rld::to_string (++arg);
380        }
381      }
382      else
383      {
384        ds += "void";
385      }
386      ds += ')';
387      return ds;
388    }
389
390    function::function (rld::config::config& config,
391                        const std::string&   name)
392      : name (name)
393    {
394      /*
395       * A function section optionally contain one or more records of:
396       *
397       * # headers     A list of sections containing headers or header records.
398       * # header      A list of include string that are single or double quoted.
399       * # defines     A list of sections containing defines or define record.
400       * # defines     A list of define string that are single or double quoted.
401       * # signatures  A list of section names of signatures.
402       * # includes    A list of files to include.
403       *
404       * @note The quoting and list spliting is a little weak because a delimiter
405       *       in a quote should not be seen as a delimiter.
406       */
407      const rld::config::section& section = config.get_section (name);
408
409      config.includes (section);
410
411      parse (config, section, "headers", "header", headers);
412      parse (config, section, "defines", "define", defines);
413
414      rld::strings sig_list;
415      section.get_record_items ("signatures", sig_list);
416
417      for (rld::strings::const_iterator sli = sig_list.begin ();
418           sli != sig_list.end ();
419           ++sli)
420      {
421        rld::strings sigs;
422        rld::split(sigs, *sli, ',');
423
424        for (rld::strings::const_iterator ssi = sigs.begin ();
425             ssi != sigs.end ();
426             ++ssi)
427        {
428          const rld::config::section& sig_sec = config.get_section (*ssi);
429          for (rld::config::records::const_iterator si = sig_sec.recs.begin ();
430               si != sig_sec.recs.end ();
431               ++si)
432          {
433            signature sig (*si);
434            signatures_[sig.name] = sig;
435          }
436        }
437      }
438    }
439
440    void
441    function::dump (std::ostream& out) const
442    {
443      out << "   Function: " << name << std::endl
444          << "    Headers: " << headers.size () << std::endl;
445      for (rld::strings::const_iterator hi = headers.begin ();
446           hi != headers.end ();
447           ++hi)
448      {
449        out << "     " << (*hi) << std::endl;
450      }
451      out << "   Defines: " << defines.size () << std::endl;
452      for (rld::strings::const_iterator di = defines.begin ();
453           di != defines.end ();
454           ++di)
455      {
456        out << "     " << (*di) << std::endl;
457      }
458      out << "   Signatures: " << signatures_.size () << std::endl;
459      for (signatures::const_iterator si = signatures_.begin ();
460           si != signatures_.end ();
461           ++si)
462      {
463        const signature& sig = (*si).second;
464        out << "     " << sig.name << ": " << sig.decl () << ';' << std::endl;
465      }
466    }
467
468    generator::generator ()
469    {
470    }
471
472    generator::generator (rld::config::config& config,
473                          const std::string&   name)
474      : name (name)
475    {
476      /*
477       * A generator section optionally contain one or more records of:
478       *
479       * # headers     A list of sections containing headers or header records.
480       * # header      A list of include string that are single or double quoted.
481       * # defines     A list of sections containing defines or define record.
482       * # defines     A list of define string that are single or double quoted.
483       * # code-blocks A list of section names of code blocks.
484       * # includes    A list of files to include.
485       *
486       * @note The quoting and list spliting is a little weak because a delimiter
487       *       in a quote should not be seen as a delimiter.
488       */
489      const rld::config::section& section = config.get_section (name);
490
491      config.includes (section);
492
493      parse (config, section, "headers",     "header", headers);
494      parse (config, section, "defines",     "define", defines);
495      parse (config, section, "code-blocks", "code",   code, false);
496
497      if (section.has_record ("entry-trace"))
498        entry_trace = rld::dequote (section.get_record_item ("entry-trace"));
499      if (section.has_record ("arg-trace"))
500        arg_trace = rld::dequote (section.get_record_item ("arg-trace"));
501      if (section.has_record ("exit-trace"))
502        exit_trace = rld::dequote (section.get_record_item ("exit-trace"));
503      if (section.has_record ("ret-trace"))
504        ret_trace = rld::dequote (section.get_record_item ("ret-trace"));
505    }
506
507    void
508    generator::dump (std::ostream& out) const
509    {
510      out << "  Generator: " << name << std::endl
511          << "   Headers: " << headers.size () << std::endl;
512      for (rld::strings::const_iterator hi = headers.begin ();
513           hi != headers.end ();
514           ++hi)
515      {
516        out << "    " << (*hi) << std::endl;
517      }
518      out << "   Defines: " << defines.size () << std::endl;
519      for (rld::strings::const_iterator di = defines.begin ();
520           di != defines.end ();
521           ++di)
522      {
523        out << "    " << (*di) << std::endl;
524      }
525      out << "   Arg Trace Code: " << arg_trace << std::endl
526          << "   Return Trace Code: " << ret_trace << std::endl
527          << "   Code blocks: " << std::endl;
528      for (rld::strings::const_iterator ci = code.begin ();
529           ci != code.end ();
530           ++ci)
531      {
532        out << "      > "
533            << rld::find_replace (*ci, "\n", "\n      | ") << std::endl;
534      }
535    }
536
537    tracer::tracer ()
538    {
539    }
540
541    void
542    tracer::load (rld::config::config& config,
543                  const std::string&   tname)
544    {
545      /*
546       * The configuration must contain a "section" section. This is the top level
547       * configuration and may contain:
548       *
549       *  # name      The name of trace being linked.
550       *  # options   A list of options as per the long command line args.
551       *  # traces    The list of sections containing function lists to trace.
552       *  # functions The list of sections containing function details.
553       *  # include   The list of files to include.
554       *
555       * The following records are required:
556       *
557       *  # name
558       *  # traces
559       *  # functions
560       */
561      const rld::config::section& section = config.get_section (tname);
562
563      name = section.get_record_item ("name");
564      load_options (section);
565      config.includes (section);
566      load_functions (config, section);
567      load_traces (config, section);
568    }
569
570    void
571    tracer::load_options (const rld::config::section& section)
572    {
573      rld::strings ol;
574      rld::config::parse_items (section, "options", ol, true);
575
576      for (rld::strings::const_iterator oli = ol.begin ();
577           oli != ol.end ();
578           ++oli)
579      {
580        rld::strings opts;
581        rld::split(opts, *oli, ',');
582        for (rld::strings::const_iterator oi = opts.begin ();
583             oi != opts.end ();
584             ++oi)
585        {
586          const std::string& opt = *oi;
587          if (opt == "dump-on-error")
588            dump_on_error = true;
589          else if (opt == "verbose")
590            rld::verbose_inc ();
591          else if (opt == "prefix")
592          {
593            rld::strings prefix;
594            rld::split (prefix, opt, '=');
595            if (prefix.size () != 2)
596              throw rld::error ("invalid option", "option: " + opt);
597            rld::cc::set_exec_prefix (prefix[1]);
598          }
599          else if (opt == "cc")
600          {
601            rld::strings cc;
602            rld::split (cc, opt, '=');
603            if (cc.size () != 2)
604              throw rld::error ("invalid option", "option: " + opt);
605            rld::cc::set_cc (cc[1]);
606          }
607          else if (opt == "ld")
608          {
609            rld::strings ld;
610            rld::split (ld, opt, '=');
611            if (ld.size () != 2)
612              throw rld::error ("invalid option", "option: " + opt);
613            rld::cc::set_ld (ld[1]);
614          }
615          else if (opt == "cflags")
616          {
617            rld::strings cflags;
618            rld::split (cflags, opt, '=');
619            if (cflags.size () < 2)
620              throw rld::error ("invalid option", "option: " + opt);
621            cflags.erase (cflags.begin ());
622            rld::cc::append_flags (rld::join (cflags, "="), rld::cc::ft_cflags);
623          }
624        }
625      }
626    }
627
628    void
629    tracer::load_functions (rld::config::config&        config,
630                            const rld::config::section& section)
631    {
632      rld::strings fl;
633      rld::config::parse_items (section, "functions", fl, true);
634      for (rld::strings::const_iterator fli = fl.begin ();
635           fli != fl.end ();
636           ++fli)
637      {
638        functions_.push_back (function (config, *fli));
639      }
640    }
641
642    void
643    tracer::load_traces (rld::config::config&        config,
644                         const rld::config::section& section)
645    {
646      parse (config, section, "traces", "trace", traces);
647
648      rld::strings gens;
649      std::string  gen;
650
651      parse (config, section, "traces", "generator", gens);
652
653      if (gens.size () > 1)
654      {
655        if (dump_on_error)
656          dump (std::cout);
657        throw rld::error ("duplicate generators", "tracer: " + section.name);
658      }
659
660      if (gens.size () == 0)
661      {
662        const rld::config::section& dg_section = config.get_section ("default-generator");
663        gen = dg_section.get_record_item ("generator");
664        config.includes (dg_section);
665      }
666      else
667      {
668        gen = gens[0];
669      }
670
671      generator_ = generator (config, gen);
672    }
673
674    void
675    tracer::generate (rld::process::tempfile& c)
676    {
677      c.open (true);
678
679      if (rld::verbose ())
680        std::cout << "wrapper C file: " << c.name () << std::endl;
681
682      try
683      {
684        c.write_line ("/*");
685        c.write_line (" * RTEMS Trace Linker Wrapper");
686        c.write_line (" *  Automatically generated.");
687        c.write_line (" */");
688
689        c.write_line ("");
690        c.write_line ("/*");
691        c.write_line (" * Generator: " + generator_.name);
692        c.write_line (" */");
693        c.write_lines (generator_.defines);
694        c.write_lines (generator_.headers);
695        c.write_line ("");
696        c.write_lines (generator_.code);
697
698        generate_traces (c);
699      }
700      catch (...)
701      {
702        c.close ();
703        if (dump_on_error)
704          dump (std::cout);
705        throw;
706      }
707
708      c.close ();
709
710      if (rld::verbose (RLD_VERBOSE_DETAILS))
711      {
712        std::cout << "Generated C file:" << std::endl;
713        c.output (" ", std::cout, true);
714      }
715    }
716
717    void
718    tracer::generate_traces (rld::process::tempfile& c)
719    {
720      for (functions::const_iterator fi = functions_.begin ();
721           fi != functions_.end ();
722           ++fi)
723      {
724        const function& funcs = *fi;
725
726        for (rld::strings::const_iterator ti = traces.begin ();
727             ti != traces.end ();
728             ++ti)
729        {
730          const std::string&         trace = *ti;
731          signatures::const_iterator si = funcs.signatures_.find (trace);
732
733          if (si != funcs.signatures_.end ())
734          {
735            c.write_line ("");
736            c.write_line ("/*");
737            c.write_line (" * Function: " + funcs.name);
738            c.write_line (" */");
739            c.write_lines (funcs.defines);
740            c.write_lines (funcs.headers);
741            break;
742          }
743        }
744      }
745
746      c.write_line ("");
747      c.write_line ("/*");
748      c.write_line (" * Wrappers.");
749      c.write_line (" */");
750
751      for (rld::strings::const_iterator ti = traces.begin ();
752           ti != traces.end ();
753           ++ti)
754      {
755        const std::string& trace = *ti;
756        bool               found = false;
757
758        for (functions::const_iterator fi = functions_.begin ();
759             fi != functions_.end ();
760             ++fi)
761        {
762          const function&            funcs = *fi;
763          signatures::const_iterator si = funcs.signatures_.find (trace);
764
765          if (si != funcs.signatures_.end ())
766          {
767            found = true;
768
769            const signature& sig = (*si).second;
770
771            c.write_line("");
772            c.write_line(sig.decl () + ";");
773            c.write_line(sig.decl ("__real_") + ";");
774            c.write_line(sig.decl ("__wrap_"));
775            c.write_line("{");
776
777            if (sig.has_ret ())
778              c.write_line(" " + sig.ret + " ret;");
779
780            std::string l;
781
782            if (!generator_.entry_trace.empty ())
783            {
784              std::string l = ' ' + generator_.entry_trace;
785              l = rld::find_replace (l, "@FUNC_NAME@", '"' + sig.name + '"');
786              l = rld::find_replace (l, "@FUNC_LABEL@", sig.name);
787              c.write_line(l);
788            }
789
790            if (sig.has_args ())
791            {
792              for (size_t a = 0; a < sig.args.size (); ++a)
793              {
794                std::string l = ' ' + generator_.arg_trace;
795                std::string n = rld::to_string ((int) (a + 1));
796                l = rld::find_replace (l, "@ARG_NUM@", n);
797                l = rld::find_replace (l, "@ARG_TYPE@", '"' + sig.args[a] + '"');
798                l = rld::find_replace (l, "@ARG_SIZE@", "sizeof(" + sig.args[a] + ')');
799                l = rld::find_replace (l, "@ARG_LABEL@", "a" + n);
800                c.write_line(l);
801              }
802            }
803
804            l.clear ();
805
806            if (sig.has_ret ())
807              l = " ret =";
808
809            l += " __real_" + sig.name + '(';
810            if (sig.has_args ())
811            {
812              for (size_t a = 0; a < sig.args.size (); ++a)
813              {
814                if (a)
815                  l += ", ";
816                l += "a" + rld::to_string ((int) (a + 1));
817              }
818            }
819            l += ");";
820            c.write_line(l);
821
822            if (!generator_.exit_trace.empty ())
823            {
824              std::string l = ' ' + generator_.exit_trace;
825              l = rld::find_replace (l, "@FUNC_NAME@", '"' + sig.name + '"');
826              l = rld::find_replace (l, "@FUNC_LABEL@", sig.name);
827              c.write_line(l);
828            }
829
830            if (sig.has_ret () && !generator_.ret_trace.empty ())
831            {
832              std::string l = ' ' + generator_.ret_trace;
833              l = rld::find_replace (l, "@RET_TYPE@", '"' + sig.ret + '"');
834              l = rld::find_replace (l, "@RET_SIZE@", "sizeof(" + sig.ret + ')');
835              l = rld::find_replace (l, "@RET_LABEL@", "ret");
836              c.write_line(l);
837              c.write_line(" return ret;");
838            }
839
840            c.write_line("}");
841          }
842        }
843
844        if (!found)
845          throw rld::error ("not found", "trace function: " + trace);
846      }
847    }
848
849    const rld::strings&
850    tracer::get_traces () const
851    {
852      return traces;
853    }
854
855    void
856    tracer::dump (std::ostream& out) const
857    {
858      out << " Tracer: " << name << std::endl
859          << "  Traces: " << traces.size () << std::endl;
860      for (rld::strings::const_iterator ti = traces.begin ();
861           ti != traces.end ();
862           ++ti)
863      {
864        out << "   " << (*ti) << std::endl;
865      }
866      out << "  Functions: " << functions_.size () << std::endl;
867      for (functions::const_iterator fi = functions_.begin ();
868           fi != functions_.end ();
869           ++fi)
870      {
871        (*fi).dump (out);
872      }
873      out << "  Generator: " << std::endl;
874      generator_.dump (out);
875    }
876
877    linker::linker ()
878    {
879    }
880
881    void
882    linker::load_config (const std::string& path,
883                         const std::string& trace)
884    {
885      std::string sp = get_prefix ();
886
887      rld::path::path_join (sp, "share", sp);
888      rld::path::path_join (sp, "rtems", sp);
889      rld::path::path_join (sp, "trace-linker", sp);
890
891      if (rld::verbose ())
892        std::cout << "search path: " << sp << std::endl;
893
894      config.set_search_path (sp);
895      config.clear ();
896      config.load (path);
897      tracer_.load (config, trace);
898    }
899
900    void
901    linker::generate_wrapper (rld::process::tempfile& c)
902    {
903      tracer_.generate (c);
904    }
905
906    void
907    linker::compile_wrapper (rld::process::tempfile& c,
908                             rld::process::tempfile& o)
909    {
910     rld::process::arg_container args;
911
912      if (rld::verbose ())
913        std::cout << "wrapper O file: " << o.name () << std::endl;
914
915      rld::cc::make_cc_command (args);
916      rld::cc::append_flags (rld::cc::ft_cflags, args);
917
918      args.push_back ("-O2");
919      args.push_back ("-g");
920      args.push_back ("-c");
921      args.push_back ("-o");
922      args.push_back (o.name ());
923      args.push_back (c.name ());
924
925      rld::process::tempfile out;
926      rld::process::tempfile err;
927      rld::process::status   status;
928
929      status = rld::process::execute (rld::cc::get_cc (),
930                                      args,
931                                      out.name (),
932                                      err.name ());
933
934      if ((status.type != rld::process::status::normal) ||
935          (status.code != 0))
936      {
937        err.output (rld::cc::get_cc (), std::cout);
938        if (dump_on_error)
939          dump (std::cout);
940        throw rld::error ("Compiler error", "compiling wrapper");
941      }
942    }
943
944    void
945    linker::link (rld::process::tempfile& o,
946                  const std::string&      ld_cmd)
947    {
948     rld::process::arg_container args;
949
950      if (rld::verbose ())
951        std::cout << "linking: " << o.name () << std::endl;
952
953      std::string wrap = " -Wl,--wrap=";
954
955      rld::cc::make_ld_command (args);
956
957      rld::process::args_append (args,
958                                 wrap + rld::join (tracer_.get_traces (), wrap));
959      args.push_back (o.name ());
960      rld::process::args_append (args, ld_cmd);
961
962      rld::process::tempfile out;
963      rld::process::tempfile err;
964      rld::process::status   status;
965
966      status = rld::process::execute (rld::cc::get_ld (),
967                                      args,
968                                      out.name (),
969                                      err.name ());
970
971      if ((status.type != rld::process::status::normal) ||
972          (status.code != 0))
973      {
974        err.output (rld::cc::get_ld (), std::cout);
975        throw rld::error ("Linker error", "linking");
976      }
977      err.output (rld::cc::get_ld (), std::cout);
978    }
979
980    void
981    linker::dump (std::ostream& out) const
982    {
983      const rld::config::paths& cpaths = config.get_paths ();
984      out << " Configuration Files: " << cpaths.size () << std::endl;
985      for (rld::config::paths::const_iterator pi = cpaths.begin ();
986           pi != cpaths.end ();
987           ++pi)
988      {
989        out << "  " << (*pi) << std::endl;
990      }
991
992      tracer_.dump (out);
993    }
994  }
995}
996
997/**
998 * RTEMS Trace Linker options. This needs to be rewritten to be like cc where
999 * only a single '-' and long options is present. Anything after '--' is passed
1000 * to RTEMS's real linker.
1001 */
1002static struct option rld_opts[] = {
1003  { "help",        no_argument,            NULL,           'h' },
1004  { "version",     no_argument,            NULL,           'V' },
1005  { "verbose",     no_argument,            NULL,           'v' },
1006  { "warn",        no_argument,            NULL,           'w' },
1007  { "keep",        no_argument,            NULL,           'k' },
1008  { "compiler",    required_argument,      NULL,           'c' },
1009  { "linker",      required_argument,      NULL,           'l' },
1010  { "exec-prefix", required_argument,      NULL,           'E' },
1011  { "cflags",      required_argument,      NULL,           'f' },
1012  { "rtems",       required_argument,      NULL,           'r' },
1013  { "rtems-bsp",   required_argument,      NULL,           'B' },
1014  { "config",      required_argument,      NULL,           'C' },
1015  { "wrapper",     required_argument,      NULL,           'W' },
1016  { NULL,          0,                      NULL,            0 }
1017};
1018
1019void
1020usage (int exit_code)
1021{
1022  std::cout << "rtems-trace-ld [options] objects" << std::endl
1023            << "Options and arguments:" << std::endl
1024            << " -h          : help (also --help)" << std::endl
1025            << " -V          : print linker version number and exit (also --version)" << std::endl
1026            << " -v          : verbose (trace import parts), can supply multiple times" << std::endl
1027            << "               to increase verbosity (also --verbose)" << std::endl
1028            << " -w          : generate warnings (also --warn)" << std::endl
1029            << " -k          : keep temporary files (also --keep)" << std::endl
1030            << " -c compiler : target compiler is not standard (also --compiler)" << std::endl
1031            << " -l linker   : target linker is not standard (also --linker)" << std::endl
1032            << " -E prefix   : the RTEMS tool prefix (also --exec-prefix)" << std::endl
1033            << " -f cflags   : C compiler flags (also --cflags)" << std::endl
1034            << " -r path     : RTEMS path (also --rtems)" << std::endl
1035            << " -B bsp      : RTEMS arch/bsp (also --rtems-bsp)" << std::endl
1036            << " -W wrapper  : wrapper file name without ext (also --wrapper)" << std::endl
1037            << " -C ini      : user configuration INI file (also --config)" << std::endl;
1038  ::exit (exit_code);
1039}
1040
1041static void
1042fatal_signal (int signum)
1043{
1044  signal (signum, SIG_DFL);
1045
1046  rld::process::temporaries_clean_up ();
1047
1048  /*
1049   * Get the same signal again, this time not handled, so its normal effect
1050   * occurs.
1051   */
1052  kill (getpid (), signum);
1053}
1054
1055static void
1056setup_signals (void)
1057{
1058  if (signal (SIGINT, SIG_IGN) != SIG_IGN)
1059    signal (SIGINT, fatal_signal);
1060#ifdef SIGHUP
1061  if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
1062    signal (SIGHUP, fatal_signal);
1063#endif
1064  if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
1065    signal (SIGTERM, fatal_signal);
1066#ifdef SIGPIPE
1067  if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
1068    signal (SIGPIPE, fatal_signal);
1069#endif
1070#ifdef SIGCHLD
1071  signal (SIGCHLD, SIG_DFL);
1072#endif
1073}
1074
1075int
1076main (int argc, char* argv[])
1077{
1078  int ec = 0;
1079
1080  setup_signals ();
1081
1082  try
1083  {
1084    rld::trace::linker linker;
1085    std::string        cc;
1086    std::string        ld;
1087    std::string        ld_cmd;
1088    std::string        configuration;
1089    std::string        trace = "tracer";
1090    std::string        wrapper;
1091    std::string        rtems_path;
1092    std::string        rtems_arch_bsp;
1093
1094    rld::set_cmdline (argc, argv);
1095
1096    while (true)
1097    {
1098      int opt = ::getopt_long (argc, argv, "hvwkVc:l:E:f:C:r:B:W:", rld_opts, NULL);
1099      if (opt < 0)
1100        break;
1101
1102      switch (opt)
1103      {
1104        case 'V':
1105          std::cout << "rtems-trace-ld (RTEMS Trace Linker) " << rld::version ()
1106                    << std::endl;
1107          ::exit (0);
1108          break;
1109
1110        case 'v':
1111          rld::verbose_inc ();
1112          break;
1113
1114        case 'w':
1115#if HAVE_WARNINGS
1116          warnings = true;
1117#endif
1118          break;
1119
1120        case 'k':
1121          rld::process::set_keep_temporary_files ();
1122          break;
1123
1124        case 'c':
1125          cc = optarg;
1126          break;
1127
1128        case 'l':
1129          ld = optarg;
1130          break;
1131
1132        case 'E':
1133          rld::cc::set_exec_prefix (optarg);
1134          break;
1135
1136        case 'f':
1137          rld::cc::append_flags (optarg, rld::cc::ft_cflags);
1138          break;
1139
1140        case 'r':
1141          rtems_path = optarg;
1142          break;
1143
1144        case 'B':
1145          rtems_arch_bsp = optarg;
1146          break;
1147
1148        case 'C':
1149          configuration = optarg;
1150          break;
1151
1152        case 'W':
1153          wrapper = optarg;
1154          break;
1155
1156        case '?':
1157          usage (3);
1158          break;
1159
1160        case 'h':
1161          usage (0);
1162          break;
1163      }
1164    }
1165
1166    /*
1167     * Set the program name.
1168     */
1169    rld::set_progname (argv[0]);
1170
1171    argc -= optind;
1172    argv += optind;
1173
1174    if (rld::verbose ())
1175    {
1176      std::cout << "RTEMS Trace Linker " << rld::version () << std::endl;
1177      std::cout << " " << rld::get_cmdline () << std::endl;
1178    }
1179
1180    /*
1181     * Load the arch/bsp value if provided.
1182     */
1183    if (!rtems_arch_bsp.empty ())
1184    {
1185      const std::string& prefix = rld::get_prefix ();
1186      if (rtems_path.empty () && prefix.empty ())
1187        throw rld::error ("No RTEMS path provided with arch/bsp", "options");
1188      if (!rtems_path.empty ())
1189        rld::rtems::set_path (rtems_path);
1190      else
1191        rld::rtems::set_path (prefix);
1192      rld::rtems::set_arch_bsp (rtems_arch_bsp);
1193    }
1194
1195    /**
1196     * Set the compiler and/or linker if provided.
1197     */
1198    if (!cc.empty ())
1199      rld::cc::set_cc (cc);
1200    if (!ld.empty ())
1201      rld::cc::set_ld (ld);
1202
1203    /*
1204     * Load the remaining command line arguments into the linker command line.
1205     */
1206    while (argc--)
1207    {
1208      /*
1209       * Create this value because 'ld_cmd += ' ' + *argv++' fails on clang.
1210       */
1211      std::string av = *argv++;
1212      ld_cmd += ' ' + av;
1213    }
1214    ld_cmd = rld::trim (ld_cmd);
1215
1216    /*
1217     * If there are no object files there is nothing to link.
1218     */
1219    if (ld_cmd.empty ())
1220      throw rld::error ("no trace linker options", "options");
1221
1222    /*
1223     * Perform a trace link.
1224     */
1225    try
1226    {
1227      linker.load_config (configuration, trace);
1228
1229      rld::process::tempfile c (".c");
1230      rld::process::tempfile o (".o");
1231
1232      if (!wrapper.empty ())
1233      {
1234        c.override (wrapper);
1235        c.keep ();
1236        o.override (wrapper);
1237        o.keep ();
1238      }
1239
1240      linker.generate_wrapper (c);
1241      linker.compile_wrapper (c, o);
1242      linker.link (o, ld_cmd);
1243
1244      if (rld::verbose ())
1245        linker.dump (std::cout);
1246    }
1247    catch (...)
1248    {
1249      throw;
1250    }
1251
1252  }
1253  catch (rld::error re)
1254  {
1255    std::cerr << "error: "
1256              << re.where << ": " << re.what
1257              << std::endl;
1258    ec = 10;
1259  }
1260  catch (std::exception e)
1261  {
1262    int   status;
1263    char* realname;
1264    realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
1265    std::cerr << "error: exception: " << realname << " [";
1266    ::free (realname);
1267    const std::type_info &ti = typeid (e);
1268    realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
1269    std::cerr << realname << "] " << e.what () << std::endl;
1270    ::free (realname);
1271    ec = 11;
1272  }
1273  catch (...)
1274  {
1275    /*
1276     * Helps to know if this happens.
1277     */
1278    std::cout << "error: unhandled exception" << std::endl;
1279    ec = 12;
1280  }
1281
1282  return ec;
1283}
Note: See TracBrowser for help on using the repository browser.