source: rtems-tools/linkers/rtems-tld.cpp @ 435d879

4.104.115
Last change on this file since 435d879 was 5afb2b8, checked in by Chris Johns <chrisj@…>, on 09/10/14 at 03:10:20

rtems-tld: Fix warnings in the generated code.

  • Property mode set to 100644
File size: 32.4 KB
Line 
1/*
2 * Copyright (c) 2014, Chris Johns <chrisj@rtems.org>
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16/**
17 * @file
18 *
19 * @ingroup rtems_rld
20 *
21 * @brief RTEMS Trace Linker manages creating a tracable RTEMS executable.
22 *
23 */
24
25#if HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#include <algorithm>
30#include <cctype>
31#include <functional>
32#include <iostream>
33#include <locale>
34#include <sstream>
35
36#include <cxxabi.h>
37#include <signal.h>
38#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
41
42#include <getopt.h>
43
44#include <rld.h>
45#include <rld-cc.h>
46#include <rld-config.h>
47#include <rld-process.h>
48#include <rld-rtems.h>
49
50#ifndef HAVE_KILL
51#define kill(p,s) raise(s)
52#endif
53
54namespace rld
55{
56  /**
57   * RTEMS Trace Linker.
58   */
59  namespace trace
60  {
61    /**
62     * 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      if (rld::verbose (RLD_VERBOSE_DETAILS))
596      {
597        std::cout << "Generated C file:" << std::endl;
598        c.output (" ", std::cout, true);
599      }
600    }
601
602    void
603    tracer::generate_traces (rld::process::tempfile& c)
604    {
605      for (functions::const_iterator fi = functions_.begin ();
606           fi != functions_.end ();
607           ++fi)
608      {
609        const function& funcs = *fi;
610
611        for (rld::strings::const_iterator ti = traces.begin ();
612             ti != traces.end ();
613             ++ti)
614        {
615          const std::string&         trace = *ti;
616          signatures::const_iterator si = funcs.signatures_.find (trace);
617
618          if (si != funcs.signatures_.end ())
619          {
620            c.write_line ("");
621            c.write_line ("/*");
622            c.write_line (" * Function: " + funcs.name);
623            c.write_line (" */");
624            c.write_lines (funcs.defines);
625            c.write_lines (funcs.headers);
626            break;
627          }
628        }
629      }
630
631      c.write_line ("");
632      c.write_line ("/*");
633      c.write_line (" * Wrappers.");
634      c.write_line (" */");
635
636      for (rld::strings::const_iterator ti = traces.begin ();
637           ti != traces.end ();
638           ++ti)
639      {
640        const std::string& trace = *ti;
641        bool               found = false;
642
643        for (functions::const_iterator fi = functions_.begin ();
644             fi != functions_.end ();
645             ++fi)
646        {
647          const function&            funcs = *fi;
648          signatures::const_iterator si = funcs.signatures_.find (trace);
649
650          if (si != funcs.signatures_.end ())
651          {
652            found = true;
653
654            const signature& sig = (*si).second;
655
656            c.write_line("");
657            c.write_line(sig.decl () + ";");
658            c.write_line(sig.decl ("__real_") + ";");
659            c.write_line(sig.decl ("__wrap_"));
660            c.write_line("{");
661
662            /*
663             * @todo Need to define as part of the function signature if ret
664             *       processing is required.
665             */
666            bool has_ret = sig.ret != "void";
667
668            if (has_ret)
669              c.write_line(" " + sig.ret + " ret;");
670
671            std::string l;
672
673            if (!generator_.entry_trace.empty ())
674            {
675              std::string l = ' ' + generator_.entry_trace;
676              l = rld::find_replace (l, "@FUNC_NAME@", '"' + sig.name + '"');
677              l = rld::find_replace (l, "@FUNC_LABEL@", sig.name);
678              c.write_line(l);
679            }
680
681            if (!generator_.arg_trace.empty ())
682            {
683              for (size_t a = 0; a < sig.args.size (); ++a)
684              {
685                std::string l = ' ' + generator_.arg_trace;
686                std::string n = rld::to_string ((int) (a + 1));
687                l = rld::find_replace (l, "@ARG_NUM@", n);
688                l = rld::find_replace (l, "@ARG_TYPE@", '"' + sig.args[a] + '"');
689                l = rld::find_replace (l, "@ARG_SIZE@", "sizeof(" + sig.args[a] + ')');
690                l = rld::find_replace (l, "@ARG_LABEL@", "a" + n);
691                c.write_line(l);
692              }
693            }
694
695            l.clear ();
696
697            if (has_ret)
698              l = " ret =";
699
700            l += " __real_" + sig.name + '(';
701            for (size_t a = 0; a < sig.args.size (); ++a)
702            {
703              if (a)
704                l += ", ";
705              l += "a" + rld::to_string ((int) (a + 1));
706            }
707            l += ");";
708            c.write_line(l);
709
710            if (!generator_.exit_trace.empty ())
711            {
712              std::string l = ' ' + generator_.exit_trace;
713              l = rld::find_replace (l, "@FUNC_NAME@", '"' + sig.name + '"');
714              l = rld::find_replace (l, "@FUNC_LABEL@", sig.name);
715              c.write_line(l);
716            }
717
718            if (has_ret && !generator_.ret_trace.empty ())
719            {
720              std::string l = ' ' + generator_.ret_trace;
721              l = rld::find_replace (l, "@RET_TYPE@", '"' + sig.ret + '"');
722              l = rld::find_replace (l, "@RET_SIZE@", "sizeof(" + sig.ret + ')');
723              l = rld::find_replace (l, "@RET_LABEL@", "ret");
724              c.write_line(l);
725              c.write_line(" return ret;");
726            }
727
728            c.write_line("}");
729          }
730        }
731
732        if (!found)
733          throw rld::error ("not found", "trace function: " + trace);
734      }
735    }
736
737    const rld::strings&
738    tracer::get_traces () const
739    {
740      return traces;
741    }
742
743    void
744    tracer::dump (std::ostream& out) const
745    {
746      out << " Tracer: " << name << std::endl
747          << "  BSP: " << bsp << std::endl
748          << "  Traces: " << traces.size () << std::endl;
749      for (rld::strings::const_iterator ti = traces.begin ();
750           ti != traces.end ();
751           ++ti)
752      {
753        out << "   " << (*ti) << std::endl;
754      }
755      out << "  Functions: " << functions_.size () << std::endl;
756      for (functions::const_iterator fi = functions_.begin ();
757           fi != functions_.end ();
758           ++fi)
759      {
760        (*fi).dump (out);
761      }
762      out << "  Generator: " << std::endl;
763      generator_.dump (out);
764    }
765
766    linker::linker ()
767    {
768    }
769
770    void
771    linker::load_config (const std::string& path,
772                         const std::string& trace)
773    {
774      std::string sp = get_prefix ();
775
776      rld::path::path_join (sp, "share", sp);
777      rld::path::path_join (sp, "rtems", sp);
778      rld::path::path_join (sp, "trace-linker", sp);
779
780      if (rld::verbose () || true)
781        std::cout << "search path: " << sp << std::endl;
782
783      config.set_search_path (sp);
784      config.clear ();
785      config.load (path);
786      tracer_.load (config, trace);
787    }
788
789    void
790    linker::generate_wrapper (rld::process::tempfile& c)
791    {
792      tracer_.generate (c);
793    }
794
795    void
796    linker::compile_wrapper (rld::process::tempfile& c,
797                             rld::process::tempfile& o)
798    {
799     rld::process::arg_container args;
800
801      if (rld::verbose ())
802        std::cout << "wrapper O file: " << o.name () << std::endl;
803
804      rld::cc::make_cc_command (args);
805      rld::cc::append_flags (rld::cc::ft_cflags, args);
806
807      args.push_back ("-O2");
808      args.push_back ("-g");
809      args.push_back ("-c");
810      args.push_back ("-o");
811      args.push_back (o.name ());
812      args.push_back (c.name ());
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_cc (),
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_cc (), std::cout);
827        throw rld::error ("Compiler error", "compiling wrapper");
828      }
829    }
830
831    void
832    linker::link (rld::process::tempfile& o,
833                  const std::string&      ld_cmd)
834    {
835     rld::process::arg_container args;
836
837      if (rld::verbose ())
838        std::cout << "linking: " << o.name () << std::endl;
839
840      std::string wrap = " -Wl,--wrap=";
841
842      rld::cc::make_ld_command (args);
843
844      rld::process::args_append (args,
845                                 wrap + rld::join (tracer_.get_traces (), wrap));
846      args.push_back (o.name ());
847      rld::process::args_append (args, ld_cmd);
848
849      rld::process::tempfile out;
850      rld::process::tempfile err;
851      rld::process::status   status;
852
853      status = rld::process::execute (rld::cc::get_ld (),
854                                      args,
855                                      out.name (),
856                                      err.name ());
857
858      if ((status.type != rld::process::status::normal) ||
859          (status.code != 0))
860      {
861        err.output (rld::cc::get_ld (), std::cout);
862        throw rld::error ("Linker error", "linking");
863      }
864      err.output (rld::cc::get_ld (), std::cout);
865    }
866
867    void
868    linker::dump (std::ostream& out) const
869    {
870      const rld::config::paths& cpaths = config.get_paths ();
871      out << " Configuration Files: " << cpaths.size () << std::endl;
872      for (rld::config::paths::const_iterator pi = cpaths.begin ();
873           pi != cpaths.end ();
874           ++pi)
875      {
876        out << "  " << (*pi) << std::endl;
877      }
878
879      tracer_.dump (out);
880    }
881  }
882}
883
884/**
885 * RTEMS Trace Linker options. This needs to be rewritten to be like cc where
886 * only a single '-' and long options is present. Anything after '--' is passed
887 * to RTEMS's real linker.
888 */
889static struct option rld_opts[] = {
890  { "help",        no_argument,            NULL,           'h' },
891  { "version",     no_argument,            NULL,           'V' },
892  { "verbose",     no_argument,            NULL,           'v' },
893  { "warn",        no_argument,            NULL,           'w' },
894  { "keep",        no_argument,            NULL,           'k' },
895  { "compiler",    required_argument,      NULL,           'c' },
896  { "linker",      required_argument,      NULL,           'l' },
897  { "exec-prefix", required_argument,      NULL,           'E' },
898  { "cflags",      required_argument,      NULL,           'f' },
899  { "rtems",       required_argument,      NULL,           'r' },
900  { "rtems-bsp",   required_argument,      NULL,           'B' },
901  { "config",      required_argument,      NULL,           'C' },
902  { "wrapper",     required_argument,      NULL,           'W' },
903  { NULL,          0,                      NULL,            0 }
904};
905
906void
907usage (int exit_code)
908{
909  std::cout << "rtems-trace-ld [options] objects" << std::endl
910            << "Options and arguments:" << std::endl
911            << " -h          : help (also --help)" << std::endl
912            << " -V          : print linker version number and exit (also --version)" << std::endl
913            << " -v          : verbose (trace import parts), can supply multiple times" << std::endl
914            << "               to increase verbosity (also --verbose)" << std::endl
915            << " -w          : generate warnings (also --warn)" << std::endl
916            << " -k          : keep temporary files (also --keep)" << std::endl
917            << " -c compiler : target compiler is not standard (also --compiler)" << std::endl
918            << " -l linker   : target linker is not standard (also --linker)" << std::endl
919            << " -E prefix   : the RTEMS tool prefix (also --exec-prefix)" << std::endl
920            << " -f cflags   : C compiler flags (also --cflags)" << std::endl
921            << " -r path     : RTEMS path (also --rtems)" << std::endl
922            << " -B bsp      : RTEMS arch/bsp (also --rtems-bsp)" << std::endl
923            << " -W wrappe r : wrapper file name without ext (also --wrapper)" << std::endl
924            << " -C ini      : user configuration INI file (also --config)" << std::endl;
925  ::exit (exit_code);
926}
927
928static void
929fatal_signal (int signum)
930{
931  signal (signum, SIG_DFL);
932
933  rld::process::temporaries_clean_up ();
934
935  /*
936   * Get the same signal again, this time not handled, so its normal effect
937   * occurs.
938   */
939  kill (getpid (), signum);
940}
941
942static void
943setup_signals (void)
944{
945  if (signal (SIGINT, SIG_IGN) != SIG_IGN)
946    signal (SIGINT, fatal_signal);
947#ifdef SIGHUP
948  if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
949    signal (SIGHUP, fatal_signal);
950#endif
951  if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
952    signal (SIGTERM, fatal_signal);
953#ifdef SIGPIPE
954  if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
955    signal (SIGPIPE, fatal_signal);
956#endif
957#ifdef SIGCHLD
958  signal (SIGCHLD, SIG_DFL);
959#endif
960}
961
962int
963main (int argc, char* argv[])
964{
965  int ec = 0;
966
967  setup_signals ();
968
969  try
970  {
971    rld::trace::linker linker;
972    std::string        cc;
973    std::string        ld;
974    std::string        ld_cmd;
975    std::string        configuration;
976    std::string        trace = "tracer";
977    std::string        wrapper;
978    std::string        rtems_path;
979    std::string        rtems_arch_bsp;
980
981    rld::set_cmdline (argc, argv);
982
983    while (true)
984    {
985      int opt = ::getopt_long (argc, argv, "hvwkVc:l:E:f:C:r:B:W:", rld_opts, NULL);
986      if (opt < 0)
987        break;
988
989      switch (opt)
990      {
991        case 'V':
992          std::cout << "rtems-trace-ld (RTEMS Trace Linker) " << rld::version ()
993                    << std::endl;
994          ::exit (0);
995          break;
996
997        case 'v':
998          rld::verbose_inc ();
999          break;
1000
1001        case 'w':
1002#if HAVE_WARNINGS
1003          warnings = true;
1004#endif
1005          break;
1006
1007        case 'k':
1008          rld::process::set_keep_temporary_files ();
1009          break;
1010
1011        case 'c':
1012          cc = optarg;
1013          break;
1014
1015        case 'l':
1016          ld = optarg;
1017          break;
1018
1019        case 'E':
1020          rld::cc::set_exec_prefix (optarg);
1021          break;
1022
1023        case 'f':
1024          rld::cc::append_flags (optarg, rld::cc::ft_cflags);
1025          break;
1026
1027        case 'r':
1028          rtems_path = optarg;
1029          break;
1030
1031        case 'B':
1032          rtems_arch_bsp = optarg;
1033          break;
1034
1035        case 'C':
1036          configuration = optarg;
1037          break;
1038
1039        case 'W':
1040          wrapper = optarg;
1041          break;
1042
1043        case '?':
1044          usage (3);
1045          break;
1046
1047        case 'h':
1048          usage (0);
1049          break;
1050      }
1051    }
1052
1053    /*
1054     * Set the program name.
1055     */
1056    rld::set_progname (argv[0]);
1057
1058    argc -= optind;
1059    argv += optind;
1060
1061    if (rld::verbose ())
1062    {
1063      std::cout << "RTEMS Trace Linker " << rld::version () << std::endl;
1064      std::cout << " " << rld::get_cmdline () << std::endl;
1065    }
1066
1067    /*
1068     * Load the arch/bsp value if provided.
1069     */
1070    if (!rtems_arch_bsp.empty ())
1071    {
1072      const std::string& prefix = rld::get_prefix ();
1073      if (rtems_path.empty () && prefix.empty ())
1074        throw rld::error ("No RTEMS path provided with arch/bsp", "options");
1075      if (!rtems_path.empty ())
1076        rld::rtems::set_path (rtems_path);
1077      else
1078        rld::rtems::set_path (prefix);
1079      rld::rtems::set_arch_bsp (rtems_arch_bsp);
1080    }
1081
1082    /**
1083     * Set the compiler and/or linker if provided.
1084     */
1085    if (!cc.empty ())
1086      rld::cc::set_cc (cc);
1087    if (!ld.empty ())
1088      rld::cc::set_ld (ld);
1089
1090    /*
1091     * Load the remaining command line arguments into the linker command line.
1092     */
1093    while (argc--)
1094    {
1095      /*
1096       * Create this value because 'ld_cmd += ' ' + *argv++' fails on clang.
1097       */
1098      std::string av = *argv++;
1099      ld_cmd += ' ' + av;
1100    }
1101    ld_cmd = rld::trim (ld_cmd);
1102
1103    /*
1104     * If there are no object files there is nothing to link.
1105     */
1106    if (ld_cmd.empty ())
1107      throw rld::error ("no trace linker options", "options");
1108
1109    /*
1110     * Perform a trace link.
1111     */
1112    try
1113    {
1114      linker.load_config (configuration, trace);
1115
1116      rld::process::tempfile c (".c");
1117      rld::process::tempfile o (".o");
1118
1119      if (!wrapper.empty ())
1120      {
1121        c.override (wrapper);
1122        c.keep ();
1123        o.override (wrapper);
1124        o.keep ();
1125      }
1126
1127      linker.generate_wrapper (c);
1128      linker.compile_wrapper (c, o);
1129      linker.link (o, ld_cmd);
1130
1131      if (rld::verbose ())
1132        linker.dump (std::cout);
1133    }
1134    catch (...)
1135    {
1136      throw;
1137    }
1138
1139  }
1140  catch (rld::error re)
1141  {
1142    std::cerr << "error: "
1143              << re.where << ": " << re.what
1144              << std::endl;
1145    ec = 10;
1146  }
1147  catch (std::exception e)
1148  {
1149    int   status;
1150    char* realname;
1151    realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
1152    std::cerr << "error: exception: " << realname << " [";
1153    ::free (realname);
1154    const std::type_info &ti = typeid (e);
1155    realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
1156    std::cerr << realname << "] " << e.what () << std::endl;
1157    ::free (realname);
1158    ec = 11;
1159  }
1160  catch (...)
1161  {
1162    /*
1163     * Helps to know if this happens.
1164     */
1165    std::cout << "error: unhandled exception" << std::endl;
1166    ec = 12;
1167  }
1168
1169  return ec;
1170}
Note: See TracBrowser for help on using the repository browser.