source: rtems-tools/linkers/rtems-tld.cpp @ 6fb1409

4.104.115
Last change on this file since 6fb1409 was 6fb1409, checked in by Chris Johns <chrisj@…>, on Sep 8, 2014 at 10:20:41 PM

rtems-tld: Add entry and exit trace support.

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