source: rtems-tools/linkers/rtems-tld.cpp @ 2126ea7

4.104.115
Last change on this file since 2126ea7 was 2126ea7, checked in by Chris Johns <chrisj@…>, on 09/08/14 at 09:29:41

rtems-tld: Generate arg and ret code in the wrapper.

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