source: rtems-tools/linkers/rtems-tld.cpp @ 17c8364

4.104.115
Last change on this file since 17c8364 was 6506aa1, checked in by Chris Johns <chrisj@…>, on 09/08/14 at 06:06:48

RTEMS trace linker builds trace applications.

The trace linker builds the both_hello example in examples-v2.

Move the various string support functions into a C++ file and stop being
inlined. Make them return const std::string.

Add ld support to rld-cc.

Add search path support to rld-config so installed common files can be used.

Fix the path bugs.

Add an absolute path function to rld-path.

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