source: rtems-tools/linkers/rtems-tld.cpp @ 5032d71

4.104.115
Last change on this file since 5032d71 was 5032d71, checked in by Chris Johns <chrisj@…>, on 03/29/15 at 05:37:22

trace-linker: Update comments.

  • Property mode set to 100644
File size: 56.0 KB
Line 
1/*
2 * Copyright (c) 2014-2015, 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 <iomanip>
34#include <locale>
35#include <sstream>
36
37#include <cxxabi.h>
38#include <signal.h>
39#include <stdlib.h>
40#include <string.h>
41#include <unistd.h>
42
43#include <getopt.h>
44
45#include <rld.h>
46#include <rld-cc.h>
47#include <rld-config.h>
48#include <rld-process.h>
49#include <rld-rtems.h>
50
51#ifndef HAVE_KILL
52#define kill(p,s) raise(s)
53#endif
54
55namespace rld
56{
57  /**
58   * RTEMS Trace Linker.
59   */
60  namespace trace
61  {
62    /**
63     * Dump on error user option.
64     */
65    bool dump_on_error;
66
67    /**
68     * A container of arguments.
69     */
70    typedef std::vector < std::string > function_args;
71
72    /**
73     * The return value.
74     */
75    typedef std::string function_return;
76
77    /**
78     * An option is a name and value pair. We consider options as global.
79     */
80    struct option
81    {
82      std::string name;      /**< The name of this option. */
83      std::string value;     /**< The option's value.. */
84
85      /**
86       * Load the option.
87       */
88      option (const std::string& name, const std::string& value)
89        : name (name),
90          value (value) {
91      }
92    };
93
94    /**
95     * A container of options.
96     */
97    typedef std::vector < option > options;
98
99    /**
100     * A function's signature.
101     */
102    struct signature
103    {
104      std::string     name; /**< The function's name. */
105      function_args   args; /**< The function's list of arguments. */
106      function_return ret;  /**< The fuctions return value. */
107
108      /**
109       * The default constructor.
110       */
111      signature ();
112
113      /**
114       * Construct the signature loading it from the configuration.
115       */
116      signature (const rld::config::record& record);
117
118      /**
119       * Has the signature got a return value ?
120       */
121      bool has_ret () const;
122
123      /**
124       * Has the signature got any arguments ?
125       */
126      bool has_args () const;
127
128      /**
129       * Return the function's declaration.
130       */
131      const std::string decl (const std::string& prefix = "") const;
132    };
133
134    /**
135     * A container of signatures.
136     */
137    typedef std::map < std::string, signature > signatures;
138
139    /**
140     * A function is list of function signatures headers and defines that allow
141     * a function to be wrapped.
142     */
143    struct function
144    {
145      std::string  name;        /**< The name of this wrapper. */
146      rld::strings headers;     /**< Include statements. */
147      rld::strings defines;     /**< Define statements. */
148      signatures   signatures_; /**< Signatures in this function. */
149
150      /**
151       * Load the function.
152       */
153      function (rld::config::config& config,
154                const std::string&   name);
155
156      /**
157       * Dump the function.
158       */
159      void dump (std::ostream& out) const;
160    };
161
162    /**
163     * A container of functions.
164     */
165    typedef std::vector < function > functions;
166
167    /**
168     * A generator and that contains the functions used to trace arguments and
169     * return values. It also provides the implementation of those functions.
170     */
171    struct generator
172    {
173      std::string  name;            /**< The name of this wrapper. */
174      std::string  lock_local;      /**< Code template to declare a local lock variable. */
175      std::string  lock_acquire;    /**< The lock acquire if provided. */
176      std::string  lock_release;    /**< The lock release if provided. */
177      std::string  buffer_local;    /**< Code template to declare a local buffer variable. */
178      rld::strings headers;         /**< Include statements. */
179      rld::strings defines;         /**< Define statements. */
180      std::string  entry_trace;     /**< Code template to trace the function entry. */
181      std::string  entry_alloc;     /**< Code template to perform a buffer allocation. */
182      std::string  arg_trace;       /**< Code template to trace an argument. */
183      std::string  exit_trace;      /**< Code template to trace the function exit. */
184      std::string  exit_alloc;      /**< Code template to perform a buffer allocation. */
185      std::string  ret_trace;       /**< Code template to trace the return value. */
186      rld::strings code;            /**< Code block inserted before the trace code. */
187
188      /**
189       * Default constructor.
190       */
191      generator ();
192
193      /**
194       * Load the generator.
195       */
196      generator (rld::config::config& config,
197                 const std::string&   name);
198
199      /**
200       * Dump the generator.
201       */
202      void dump (std::ostream& out) const;
203    };
204
205    /**
206     * Tracer.
207     */
208    class tracer
209    {
210    public:
211      tracer ();
212
213      /**
214       * Load the user's configuration.
215       */
216      void load (rld::config::config& config,
217                 const std::string&   section);
218
219      /**
220       * Process any script based options.
221       */
222      void load_options (rld::config::config&        config,
223                         const rld::config::section& section);
224
225      /**
226       * The defines for the trace.
227       */
228      void load_defines (rld::config::config&        config,
229                         const rld::config::section& section);
230
231      /**
232       * The functions for the trace.
233       */
234      void load_functions (rld::config::config&        config,
235                           const rld::config::section& section);
236
237      /**
238       * The enables for the tracer.
239       */
240      void load_enables (rld::config::config&        config,
241                         const rld::config::section& section);
242
243      /**
244       * The triggers for the tracer.
245       */
246      void load_triggers (rld::config::config&        config,
247                          const rld::config::section& section);
248
249      /**
250       * The traces for the tracer.
251       */
252      void load_traces (rld::config::config&        config,
253                        const rld::config::section& section);
254
255      /**
256       * Get option from the options section.
257       */
258      const std::string get_option (const std::string& name) const;
259
260      /**
261       * Generate the wrapper object file.
262       */
263      void generate (rld::process::tempfile& c);
264
265      /**
266       * Generate the trace names as a string table.
267       */
268      void generate_names (rld::process::tempfile& c);
269
270      /**
271       * Generate the trace signature tables.
272       */
273      void generate_signatures (rld::process::tempfile& c);
274
275      /**
276       * Generate the enabled trace bitmap.
277       */
278      void generate_enables (rld::process::tempfile& c);
279
280      /**
281       * Generate the triggered trace bitmap.
282       */
283      void generate_triggers (rld::process::tempfile& c);
284
285      /**
286       * Generate the functions.
287       */
288      void generate_functions (rld::process::tempfile& c);
289
290      /**
291       * Generate the trace functions.
292       */
293      void generate_traces (rld::process::tempfile& c);
294
295      /**
296       * Generate a bitmap.
297       */
298      void generate_bitmap (rld::process::tempfile& c,
299                            const rld::strings&     names,
300                            const std::string&      label,
301                            const bool              global_set);
302
303      /**
304       * Function macro replace.
305       */
306      void macro_func_replace (std::string&       text,
307                               const signature&   sig,
308                               const std::string& index);
309
310      /**
311       * Find the function given a name.
312       */
313      const function& find_function (const std::string& name) const;
314
315      /**
316       * Get the traces.
317       */
318      const rld::strings& get_traces () const;
319
320      /**
321       * Dump the wrapper.
322       */
323      void dump (std::ostream& out) const;
324
325    private:
326
327      std::string  name;          /**< The name of the trace. */
328      rld::strings defines;       /**< Define statements. */
329      rld::strings enables;       /**< The default enabled functions. */
330      rld::strings triggers;      /**< The default trigger functions. */
331      rld::strings traces;        /**< The functions to trace. */
332      options      options_;      /**< The options. */
333      functions    functions_;    /**< The functions that can be traced. */
334      generator    generator_;    /**< The tracer's generator. */
335    };
336
337    /**
338     * Trace Linker.
339     */
340    class linker
341    {
342    public:
343      linker ();
344
345      /**
346       * Load the user's configuration.
347       */
348      void load_config (const std::string& name,
349                        const std::string& trace,
350                        const std::string& path);
351
352      /**
353       * Generate the C file.
354       */
355      void generate_wrapper (rld::process::tempfile& c);
356
357      /**
358       * Compile the C file.
359       */
360      void compile_wrapper (rld::process::tempfile& c,
361                            rld::process::tempfile& o);
362
363      /**
364       * Link the application.
365       */
366      void link (rld::process::tempfile& o,
367                 const std::string&      ld_cmds);
368
369      /**
370       * Dump the linker.
371       */
372      void dump (std::ostream& out) const;
373
374    private:
375
376      rld::config::config    config;     /**< User configuration. */
377      tracer                 tracer_;    /**< The tracer */
378      rld::process::tempfile c; /**< The C wrapper file */
379      rld::process::tempfile o; /**< The wrapper object file */
380    };
381
382    /**
383     * Recursive parser for strings.
384     */
385    void
386    parse (rld::config::config&        config,
387           const rld::config::section& section,
388           const std::string&          sec_name,
389           const std::string&          rec_name,
390           rld::strings&               items,
391           bool                        split = true,
392           int                         depth = 0)
393    {
394      if (depth > 32)
395        throw rld::error ("too deep", "parsing: " + sec_name + '/' + rec_name);
396
397      rld::config::parse_items (section, rec_name, items, false, false, split);
398
399      rld::strings sl;
400
401      rld::config::parse_items (section, sec_name, sl);
402
403      for (rld::strings::iterator sli = sl.begin ();
404           sli != sl.end ();
405           ++sli)
406      {
407        const rld::config::section& sec = config.get_section (*sli);
408        parse (config, sec, sec_name, rec_name, items, split, depth + 1);
409      }
410
411      /*
412       * Make the items unique.
413       */
414      rld::strings::iterator ii;
415      ii = std::unique (items.begin (), items.end ());
416      items.resize (std::distance (items.begin (), ii));
417    }
418
419    signature::signature ()
420    {
421    }
422
423    signature::signature (const rld::config::record& record)
424    {
425      /*
426       * There can only be one function signature in the configuration.
427       */
428      if (!record.single ())
429        throw rld::error ("duplicate", "signature: " + record.name);
430
431      name = record.name;
432
433      /*
434       * Signatures are defined as the return value then the arguments
435       * delimited by a comma and white space. No checking is made of the
436       * return value or arguments.
437       */
438      rld::strings si;
439      rld::config::parse_items (record, si);
440
441      if (si.size () == 0)
442        throw rld::error ("no return value", "signature: " + name);
443      if (si.size () == 1)
444          throw rld::error ("no arguments", "signature: " + name);
445
446      ret = si[0];
447      args.resize (si.size () - 1);
448      std::copy (si.begin ()  + 1, si.end (), args.begin ());
449    }
450
451    bool
452    signature::has_ret () const
453    {
454      /*
455       * @todo Need to define as part of the function signature if ret
456       *       processing is required.
457       */
458      return ret != "void";
459    }
460
461    bool
462    signature::has_args () const
463    {
464      if (args.empty ())
465          return false;
466      return ((args.size() == 1) && (args[0] == "void")) ? false : true;
467    }
468
469    const std::string
470    signature::decl (const std::string& prefix) const
471    {
472      std::string ds = ret + ' ' + prefix + name + '(';
473      if (has_args ())
474      {
475        int arg = 0;
476        for (function_args::const_iterator ai = args.begin ();
477             ai != args.end ();
478             ++ai)
479        {
480          if (ai != args.begin ())
481            ds += ", ";
482          ds += (*ai) + " a" + rld::to_string (++arg);
483        }
484      }
485      else
486      {
487        ds += "void";
488      }
489      ds += ')';
490      return ds;
491    }
492
493    function::function (rld::config::config& config,
494                        const std::string&   name)
495      : name (name)
496    {
497      /*
498       * A function section optionally contain one or more records of:
499       *
500       * # headers     A list of sections containing headers or header records.
501       * # header      A list of include string that are single or double quoted.
502       * # defines     A list of sections containing defines or define record.
503       * # defines     A list of define string that are single or double quoted.
504       * # signatures  A list of section names of signatures.
505       * # includes    A list of files to include.
506       *
507       * @note The quoting and list spliting is a little weak because a delimiter
508       *       in a quote should not be seen as a delimiter.
509       */
510      const rld::config::section& section = config.get_section (name);
511
512      config.includes (section);
513
514      parse (config, section, "headers", "header", headers);
515      parse (config, section, "defines", "define", defines);
516
517      rld::strings sig_list;
518      section.get_record_items ("signatures", sig_list);
519
520      for (rld::strings::const_iterator sli = sig_list.begin ();
521           sli != sig_list.end ();
522           ++sli)
523      {
524        rld::strings sigs;
525        rld::split(sigs, *sli, ',');
526
527        for (rld::strings::const_iterator ssi = sigs.begin ();
528             ssi != sigs.end ();
529             ++ssi)
530        {
531          const rld::config::section& sig_sec = config.get_section (*ssi);
532          for (rld::config::records::const_iterator si = sig_sec.recs.begin ();
533               si != sig_sec.recs.end ();
534               ++si)
535          {
536            signature sig (*si);
537            signatures_[sig.name] = sig;
538          }
539        }
540      }
541    }
542
543    void
544    function::dump (std::ostream& out) const
545    {
546      out << "   Function: " << name << std::endl
547          << "    Headers: " << headers.size () << std::endl;
548      for (rld::strings::const_iterator hi = headers.begin ();
549           hi != headers.end ();
550           ++hi)
551      {
552        out << "     " << (*hi) << std::endl;
553      }
554      out << "   Defines: " << defines.size () << std::endl;
555      for (rld::strings::const_iterator di = defines.begin ();
556           di != defines.end ();
557           ++di)
558      {
559        out << "     " << (*di) << std::endl;
560      }
561      out << "   Signatures: " << signatures_.size () << std::endl;
562      for (signatures::const_iterator si = signatures_.begin ();
563           si != signatures_.end ();
564           ++si)
565      {
566        const signature& sig = (*si).second;
567        out << "     " << sig.name << ": " << sig.decl () << ';' << std::endl;
568      }
569    }
570
571    generator::generator ()
572    {
573    }
574
575    generator::generator (rld::config::config& config,
576                          const std::string&   name)
577      : name (name)
578    {
579      /*
580       * A generator section optionally contain one or more records of:
581       *
582       * # headers      A list of sections containing headers or header records.
583       * # header       A list of include string that are single or double quoted.
584       * # defines      A list of sections containing defines or define record.
585       * # define       A list of define string that are single or double quoted.
586       * # entry-trace  The wrapper call made on a function's entry.  Returns `bool
587       *                where `true` is the function is being traced. This call is made
588       *                without the lock being held if a lock is defined.
589       * # arg-trace    The wrapper call made for each argment to the trace function if
590       *                the function is being traced. This call is made without the
591       *                lock being held if a lock is defined.
592       * # exit-trace   The wrapper call made after a function's exit. Returns `bool
593       *                where `true` is the function is being traced. This call is made
594       *                without the lock being held if a lock is defined.
595       * # ret-trace    The wrapper call made to log the return value if the funciton
596       *                is being traced. This call is made without the lock being held
597       *                if a lock is defined.
598       * # lock-local   The wrapper code to declare a local lock variable.
599       * # lock-acquire The wrapper code to acquire the lock.
600       * # lock-release The wrapper code to release the lock.
601       * # buffer-local The wrapper code to declare a buffer index local variable.
602       * # buffer-alloc The wrapper call made with a lock held if defined to allocate
603       *                buffer space to hold the trace data. A suitable 32bit buffer
604       *                index is returned. If there is no space an invalid index is
605       *                returned. The generator must handle any overhead space needed.
606       *                the generator needs to make sure the space is available before
607       *                making the alloc all.
608       * # code-blocks  A list of code blcok section names.
609       * # code         A code block in `<<CODE ... CODE` (without the single quote).
610       * # includes     A list of files to include.
611       *
612       * The following macros can be used in specific wrapper calls. The lists of
613       * where you can use them is listed before. The macros are:
614       *
615       * # @FUNC_NAME@            The trace function name as a quote C string.
616       * # @FUNC_INDEX@           The trace function index as a held in the
617       *                          sorted list of trace functions by teh trace
618       *                          linker. It can be used to index the `names`,
619       *                          `enables` and `triggers` data.
620       * # @FUNC_LABEL@           The trace function name as a C label that can
621       *                          be referenced. You can take the address of
622       *                          the label.
623       * # @FUNC_DATA_SIZE@       The size of the data in bytes.
624       * # @FUNC_DATA_ENTRY_SIZE@ The size of the entry data in bytes.
625       * # @FUNC_DATA_RET_SIZE@   The size of the return data in bytes.
626       * # @ARG_NUM@              The argument number to the trace function.
627       * # @ARG_TYPE@             The type of the argument as a C string.
628       * # @ARG_SIZE@             The size of the type of the argument in bytes.
629       * # @ARG_LABEL@            The argument as a C label that can be referenced.
630       * # @RET_TYPE@             The type of the return value as a C string.
631       * # @RET_SIZE@             The size of the type of the return value in bytes.
632       * # @RET_LABEL@            The return value as a C label that can be referenced.
633       *
634       * The `buffer-alloc`, `entry-trace` and `exit-trace` can be transformed using
635       *  the following  macros:
636       *
637       * # @FUNC_NAME@
638       * # @FUNC_INDEX@
639       * # @FUNC_LABEL@
640       * # @FUNC_DATA_SZIE@
641       * # @FUNC_DATA_ENTRY_SZIE@
642       * # @FUNC_DATA_EXIT_SZIE@
643       *
644       * The `arg-trace` can be transformed using the following macros:
645       *
646       * # @ARG_NUM@
647       * # @ARG_TYPE@
648       * # @ARG_SIZE@
649       * # @ARG_LABEL@
650       *
651       * The `ret-trace` can be transformed using the following macros:
652       *
653       * # @RET_TYPE@
654       * # @RET_SIZE@
655       * # @RET_LABEL@
656       *
657       * @note The quoting and list spliting is a little weak because a delimiter
658       *       in a quote should not be seen as a delimiter.
659       */
660      const rld::config::section& section = config.get_section (name);
661
662      config.includes (section);
663
664      parse (config, section, "headers",     "header", headers);
665      parse (config, section, "defines",     "define", defines);
666      parse (config, section, "code-blocks", "code",   code, false);
667
668      if (section.has_record ("lock-local"))
669        lock_local = rld::dequote (section.get_record_item ("lock-local"));
670      if (section.has_record ("lock-acquire"))
671        lock_acquire = rld::dequote (section.get_record_item ("lock-acquire"));
672      if (section.has_record ("lock-release"))
673        lock_release = rld::dequote (section.get_record_item ("lock-release"));
674      if (section.has_record ("buffer-local"))
675        buffer_local = rld::dequote (section.get_record_item ("buffer-local"));
676      if (section.has_record ("entry-trace"))
677        entry_trace = rld::dequote (section.get_record_item ("entry-trace"));
678      if (section.has_record ("entry-alloc"))
679        entry_alloc = rld::dequote (section.get_record_item ("entry-alloc"));
680      if (section.has_record ("arg-trace"))
681        arg_trace = rld::dequote (section.get_record_item ("arg-trace"));
682      if (section.has_record ("exit-trace"))
683        exit_trace = rld::dequote (section.get_record_item ("exit-trace"));
684      if (section.has_record ("exit-alloc"))
685        exit_alloc = rld::dequote (section.get_record_item ("exit-alloc"));
686      if (section.has_record ("ret-trace"))
687        ret_trace = rld::dequote (section.get_record_item ("ret-trace"));
688    }
689
690    void
691    generator::dump (std::ostream& out) const
692    {
693      out << "  Generator: " << name << std::endl
694          << "   Headers: " << headers.size () << std::endl;
695      for (rld::strings::const_iterator hi = headers.begin ();
696           hi != headers.end ();
697           ++hi)
698      {
699        out << "    " << (*hi) << std::endl;
700      }
701      out << "   Defines: " << defines.size () << std::endl;
702      for (rld::strings::const_iterator di = defines.begin ();
703           di != defines.end ();
704           ++di)
705      {
706        out << "    " << (*di) << std::endl;
707      }
708      out << "   Arg Trace Code: " << arg_trace << std::endl
709          << "   Return Trace Code: " << ret_trace << std::endl
710          << "   Code blocks: " << std::endl;
711      for (rld::strings::const_iterator ci = code.begin ();
712           ci != code.end ();
713           ++ci)
714      {
715        out << "      > "
716            << rld::find_replace (*ci, "\n", "\n      | ") << std::endl;
717      }
718    }
719
720    tracer::tracer ()
721    {
722    }
723
724    void
725    tracer::load (rld::config::config& config,
726                  const std::string&   tname)
727    {
728      /*
729       * The configuration must contain a "section" section. This is the top level
730       * configuration and may contain:
731       *
732       *  # name      The name of trace being linked.
733       *  # options   A list of option sections.
734       *  # defines   A list of sections containing defines or define record.
735       *  # define    A list of define string that are single or double quoted.
736       *  # enables   The list of sections containing enabled functions to trace.
737       *  # triggers  The list of sections containing enabled functions to trigger trace on.
738       *  # traces    The list of sections containing function lists to trace.
739       *  # functions The list of sections containing function details.
740       *  # include   The list of files to include.
741       *
742       * The following records are required:
743       *
744       *  # name
745       *  # traces
746       *  # functions
747       */
748      const rld::config::section& section = config.get_section (tname);
749
750      name = section.get_record_item ("name");
751      load_options (config, section);
752      config.includes (section);
753      load_defines (config, section);
754      load_functions (config, section);
755      load_enables (config, section);
756      load_triggers (config, section);
757      load_traces (config, section);
758    }
759
760    void
761    tracer::load_options (rld::config::config&        config,
762                          const rld::config::section& section)
763    {
764      rld::strings opts;
765      rld::config::parse_items (section, "options", opts, false, true, true);
766
767      if (rld::verbose ())
768        std::cout << "options: " << section.name << ": " << opts.size () << std::endl;
769
770      options_.clear ();
771
772      for (rld::strings::const_iterator osi = opts.begin ();
773           osi != opts.end ();
774           ++osi)
775      {
776        const rld::config::section& osec = config.get_section (*osi);
777
778        if (rld::verbose ())
779          std::cout << " options: " << osec.name
780                    << ": recs:" << osec.recs.size () << std::endl;
781
782        for (rld::config::records::const_iterator ori = osec.recs.begin ();
783             ori != osec.recs.end ();
784             ++ori)
785        {
786          const rld::config::record& opt = *ori;
787
788          if (!opt.single ())
789              throw rld::error ("mode than one option specified", "option: " + opt.name);
790
791          options_.push_back (option (opt.name, opt[0]));
792
793          if (opt.name == "dump-on-error")
794          {
795            dump_on_error = true;
796          }
797          else if (opt.name == "verbose")
798          {
799            int level = ::strtoul(opt[0].c_str (), 0, 0);
800            if (level == 0)
801              level = 1;
802            for (int l = 0; l < level; ++l)
803              rld::verbose_inc ();
804          }
805          else if (opt.name == "prefix")
806          {
807            rld::cc::set_exec_prefix (opt[0]);
808          }
809          else if (opt.name == "cc")
810          {
811            rld::cc::set_cc (opt[0]);
812          }
813          else if (opt.name == "ld")
814          {
815            rld::cc::set_ld (opt[0]);
816          }
817          else if (opt.name == "cflags")
818          {
819            rld::cc::append_flags (opt[0], rld::cc::ft_cflags);
820          }
821          else if (opt.name == "rtems-path")
822          {
823            rld::rtems::set_path(opt[0]);
824          }
825          else if (opt.name == "rtems-bsp")
826          {
827            rld::rtems::set_arch_bsp(opt[0]);
828          }
829        }
830      }
831    }
832
833    void
834    tracer::load_defines (rld::config::config&        config,
835                          const rld::config::section& section)
836    {
837      parse (config, section, "defines", "define", defines);
838    }
839
840    void
841    tracer::load_functions (rld::config::config&        config,
842                            const rld::config::section& section)
843    {
844      rld::strings fl;
845      rld::config::parse_items (section, "functions", fl, true);
846      for (rld::strings::const_iterator fli = fl.begin ();
847           fli != fl.end ();
848           ++fli)
849      {
850        functions_.push_back (function (config, *fli));
851      }
852    }
853
854    void
855    tracer::load_enables (rld::config::config&        config,
856                          const rld::config::section& section)
857    {
858      parse (config, section, "enables", "enable", enables);
859    }
860
861    void
862    tracer::load_triggers (rld::config::config&        config,
863                           const rld::config::section& section)
864    {
865      parse (config, section, "triggers", "trigger", triggers);
866    }
867
868    void
869    tracer::load_traces (rld::config::config&        config,
870                         const rld::config::section& section)
871    {
872      parse (config, section, "traces", "trace", traces);
873
874      rld::strings gens;
875      std::string  gen;
876
877      parse (config, section, "traces", "generator", gens);
878
879      if (gens.size () > 1)
880      {
881        if (dump_on_error)
882          dump (std::cout);
883        throw rld::error ("duplicate generators", "tracer: " + section.name);
884      }
885
886      if (gens.size () == 0)
887      {
888        const rld::config::section& dg_section = config.get_section ("default-generator");
889        gen = dg_section.get_record_item ("generator");
890        config.includes (dg_section);
891      }
892      else
893      {
894        gen = gens[0];
895      }
896
897      sort (traces.begin (), traces.end ());
898
899      generator_ = generator (config, gen);
900    }
901
902    const std::string
903    tracer::get_option (const std::string& name) const
904    {
905      std::string value;
906      for (options::const_iterator oi = options_.begin ();
907           oi != options_.end ();
908           ++oi)
909      {
910        const option& opt = *oi;
911        if (opt.name == name)
912        {
913          value = opt.value;
914          break;
915        }
916      }
917      return value;
918    }
919
920    void
921    tracer::generate (rld::process::tempfile& c)
922    {
923      c.open (true);
924
925      if (rld::verbose ())
926        std::cout << "wrapper C file: " << c.name () << std::endl;
927
928      try
929      {
930        c.write_line ("/*");
931        c.write_line (" * RTEMS Trace Linker Wrapper");
932        c.write_line (" *  Automatically generated.");
933        c.write_line (" */");
934
935        c.write_line ("");
936        c.write_line ("/*");
937        c.write_line (" * Tracer: " + name);
938        c.write_line (" */");
939        c.write_lines (defines);
940
941        c.write_line ("");
942        c.write_line ("/*");
943        c.write_line (" * Generator: " + generator_.name);
944        c.write_line (" */");
945        c.write_lines (generator_.defines);
946        c.write_lines (generator_.headers);
947        c.write_line ("");
948        generate_functions (c);
949        generate_names (c);
950        generate_signatures (c);
951        generate_enables (c);
952        generate_triggers (c);
953        c.write_line ("");
954        c.write_lines (generator_.code);
955
956        generate_traces (c);
957      }
958      catch (...)
959      {
960        c.close ();
961        if (dump_on_error)
962          dump (std::cout);
963        throw;
964      }
965
966      c.close ();
967
968      if (rld::verbose (RLD_VERBOSE_DETAILS))
969      {
970        std::cout << "Generated C file:" << std::endl;
971        c.output (" ", std::cout, true);
972      }
973    }
974
975    void
976    tracer::generate_names (rld::process::tempfile& c)
977    {
978      const std::string opt = get_option ("gen-names");
979
980      if (opt == "disable")
981        return;
982
983      c.write_line ("");
984      c.write_line ("/*");
985      c.write_line (" * Names.");
986      c.write_line (" */");
987
988      std::stringstream sss;
989      sss << "uint32_t __rtld_trace_names_size = " << traces.size() << ";" << std::endl
990          << "const char const* __rtld_trace_names[" << traces.size() << "] = " << std::endl
991          << "{";
992      c.write_line (sss.str ());
993
994      int count = 0;
995
996      for (rld::strings::const_iterator ti = traces.begin ();
997           ti != traces.end ();
998           ++ti)
999      {
1000        const std::string& trace = *ti;
1001        sss.str (std::string ());
1002        sss << "  /* " << std::setw (3) << count << " */ \"" << trace << "\",";
1003        c.write_line (sss.str ());
1004        ++count;
1005      }
1006
1007      c.write_line ("};");
1008    }
1009
1010    void
1011    tracer::generate_signatures (rld::process::tempfile& c)
1012    {
1013      const std::string opt = get_option ("gen-sigs");
1014
1015      if (opt == "disable")
1016        return;
1017
1018      c.write_line ("");
1019      c.write_line ("/*");
1020      c.write_line (" * Signatures.");
1021      c.write_line (" */");
1022      c.write_line ("");
1023      c.write_line ("typedef struct {");
1024      c.write_line (" uint32_t          size;");
1025      c.write_line (" const char* const type;");
1026      c.write_line ("} __rtld_trace_sig_arg;");
1027      c.write_line ("");
1028      c.write_line ("typedef struct {");
1029      c.write_line (" uint32_t                    argc;");
1030      c.write_line (" const __rtld_trace_sig_arg* args;");
1031      c.write_line ("} __rtld_trace_sig;");
1032      c.write_line ("");
1033
1034      std::stringstream sss;
1035
1036      for (rld::strings::const_iterator ti = traces.begin ();
1037           ti != traces.end ();
1038           ++ti)
1039      {
1040        const std::string& trace = *ti;
1041        bool               found = false;
1042
1043        for (functions::const_iterator fi = functions_.begin ();
1044             !found && (fi != functions_.end ());
1045             ++fi)
1046        {
1047          const function&            funcs = *fi;
1048          signatures::const_iterator si = funcs.signatures_.find (trace);
1049
1050          if (si != funcs.signatures_.end ())
1051          {
1052            found = true;
1053
1054            const signature& sig = (*si).second;
1055
1056            size_t argc = 1 + (sig.args.size () == 0 ? 1 : sig.args.size ());
1057
1058            sss.str (std::string ());
1059
1060            sss << "const __rtld_trace_sig_arg __rtld_trace_sig_args_" << trace
1061                << "[" << argc << "] =" << std::endl
1062                << "{" << std::endl;
1063
1064            if (sig.has_ret ())
1065              sss << "  { sizeof (" << sig.ret << "), \"" << sig.ret << "\" }," << std::endl;
1066            else
1067              sss << "  { 0, \"void\" }," << std::endl;
1068
1069            if (sig.has_args ())
1070            {
1071              for (size_t a = 0; a < sig.args.size (); ++a)
1072              {
1073                sss << "  { sizeof (" << sig.args[a] << "), \"" << sig.args[a] << "\" },"
1074                    << std::endl;
1075              }
1076            }
1077            else
1078              sss << "  { 0, \"void\" }," << std::endl;
1079
1080            sss << "};" << std::endl;
1081
1082            c.write_line (sss.str ());
1083          }
1084        }
1085
1086        if (!found)
1087          throw rld::error ("not found", "trace function: " + trace);
1088      }
1089
1090      sss.str (std::string ());
1091
1092      sss << "const __rtld_trace_sig __rtld_trace_signatures[" << traces.size () << "] = "
1093          << "{" << std::endl;
1094
1095      for (rld::strings::const_iterator ti = traces.begin ();
1096           ti != traces.end ();
1097           ++ti)
1098      {
1099        const std::string& trace = *ti;
1100
1101        for (functions::const_iterator fi = functions_.begin ();
1102             fi != functions_.end ();
1103             ++fi)
1104        {
1105          const function&            funcs = *fi;
1106          signatures::const_iterator si = funcs.signatures_.find (trace);
1107
1108          if (si != funcs.signatures_.end ())
1109          {
1110            const signature& sig = (*si).second;
1111            size_t argc = 1 + (sig.args.size () == 0 ? 1 : sig.args.size ());
1112            sss << "  { " << argc << ", __rtld_trace_sig_args_" << trace << " }," << std::endl;
1113            break;
1114          }
1115        }
1116      }
1117
1118      sss << "};" << std::endl;
1119
1120      c.write_line (sss.str ());
1121    }
1122
1123    void
1124    tracer::generate_enables (rld::process::tempfile& c)
1125    {
1126      const std::string opt = get_option ("gen-enables");
1127      bool              global_state = false;
1128
1129      if (opt == "disable")
1130        return;
1131
1132      if (opt == "global-on")
1133        global_state = true;
1134
1135      c.write_line ("");
1136      c.write_line ("/*");
1137      c.write_line (" * Enables.");
1138      c.write_line (" */");
1139
1140      generate_bitmap (c, enables, "enables", global_state);
1141    }
1142
1143    void
1144    tracer::generate_triggers (rld::process::tempfile& c)
1145    {
1146      const std::string opt = get_option ("gen-triggers");
1147      bool              global_state = false;
1148
1149      if (opt == "disable")
1150        return;
1151
1152      if (opt == "global-on")
1153        global_state = true;
1154
1155      c.write_line ("");
1156      c.write_line ("/*");
1157      c.write_line (" * Triggers.");
1158      c.write_line (" */");
1159
1160      generate_bitmap (c, triggers, "triggers", global_state);
1161
1162      c.write_line ("");
1163    }
1164
1165    void
1166    tracer::generate_functions (rld::process::tempfile& c)
1167    {
1168      c.write_line ("/*");
1169      c.write_line (" * Functions.");
1170      c.write_line (" */");
1171
1172      for (functions::const_iterator fi = functions_.begin ();
1173           fi != functions_.end ();
1174           ++fi)
1175      {
1176        const function& funcs = *fi;
1177
1178        for (rld::strings::const_iterator ti = traces.begin ();
1179             ti != traces.end ();
1180             ++ti)
1181        {
1182          const std::string&         trace = *ti;
1183          signatures::const_iterator si = funcs.signatures_.find (trace);
1184
1185          if (si != funcs.signatures_.end ())
1186          {
1187            c.write_line ("");
1188            c.write_line ("/*");
1189            c.write_line (" * Function: " + funcs.name);
1190            c.write_line (" */");
1191            c.write_lines (funcs.defines);
1192            c.write_lines (funcs.headers);
1193            break;
1194          }
1195        }
1196      }
1197    }
1198
1199    void
1200    tracer::generate_traces (rld::process::tempfile& c)
1201    {
1202      c.write_line ("/*");
1203      c.write_line (" * Wrappers.");
1204      c.write_line (" */");
1205
1206      size_t count = 0;
1207
1208      for (rld::strings::const_iterator ti = traces.begin ();
1209           ti != traces.end ();
1210           ++ti)
1211      {
1212        const std::string& trace = *ti;
1213        bool               found = false;
1214
1215        for (functions::const_iterator fi = functions_.begin ();
1216             fi != functions_.end ();
1217             ++fi)
1218        {
1219          const function&            funcs = *fi;
1220          signatures::const_iterator si = funcs.signatures_.find (trace);
1221
1222          if (si != funcs.signatures_.end ())
1223          {
1224            found = true;
1225
1226            const signature& sig = (*si).second;
1227
1228            std::stringstream lss;
1229            lss << count;
1230
1231            c.write_line("");
1232
1233            if (sig.has_args () || (sig.has_ret () && !generator_.ret_trace.empty ()))
1234            {
1235              std::string ds;
1236              std::string des;
1237              std::string drs;
1238              bool        ds_added = false;
1239              bool        des_added = false;
1240              bool        drs_added = false;
1241              ds  = "#define FUNC_DATA_SIZE_" + sig.name + " (";
1242              des = "#define FUNC_DATA_ENTRY_SIZE_" + sig.name + " (";
1243              drs = "#define FUNC_DATA_RET_SIZE_" + sig.name + " (";
1244              if (sig.has_args ())
1245              {
1246                for (size_t a = 0; a < sig.args.size (); ++a)
1247                {
1248                  if (ds_added)
1249                    ds += " + ";
1250                  else
1251                    ds_added = true;
1252                  if (des_added)
1253                    des += " + ";
1254                  else
1255                    des_added = true;
1256                  ds += "sizeof(" + sig.args[a] + ')';
1257                  des += "sizeof(" + sig.args[a] + ')';
1258                }
1259              }
1260              if (sig.has_ret () && !generator_.ret_trace.empty ())
1261              {
1262                if (ds_added)
1263                  ds += " + ";
1264                else
1265                  ds_added = true;
1266                if (drs_added)
1267                  drs += " + ";
1268                else
1269                  drs_added = true;
1270                ds += "sizeof(" + sig.ret + ')';
1271                drs += "sizeof(" + sig.ret + ')';
1272              }
1273              if (!ds_added)
1274                ds += '0';
1275              ds += ')';
1276              if (!des_added)
1277                des += '0';
1278              des += ')';
1279              if (!drs_added)
1280                drs += '0';
1281              drs += ')';
1282              c.write_line(ds);
1283              c.write_line(des);
1284              c.write_line(drs);
1285            }
1286
1287            c.write_line(sig.decl () + ";");
1288            c.write_line(sig.decl ("__real_") + ";");
1289            c.write_line(sig.decl ("__wrap_"));
1290            c.write_line("{");
1291
1292            if (!generator_.lock_local.empty ())
1293              c.write_line(generator_.lock_local);
1294
1295            if (!generator_.buffer_local.empty ())
1296              c.write_line(generator_.buffer_local);
1297
1298            if (sig.has_ret ())
1299              c.write_line(" " + sig.ret + " ret;");
1300
1301            std::string l;
1302
1303            if (!generator_.lock_acquire.empty ())
1304              c.write_line(generator_.lock_acquire);
1305
1306            if (!generator_.entry_alloc.empty ())
1307            {
1308              l = " " + generator_.entry_alloc;
1309              macro_func_replace (l, sig, lss.str ());
1310              c.write_line(l);
1311            }
1312
1313            if (!generator_.lock_release.empty ())
1314              c.write_line(generator_.lock_release);
1315
1316            if (!generator_.entry_trace.empty ())
1317            {
1318              l = " " + generator_.entry_trace;
1319              macro_func_replace (l, sig, lss.str ());
1320              c.write_line(l);
1321            }
1322
1323            if (sig.has_args ())
1324            {
1325              for (size_t a = 0; a < sig.args.size (); ++a)
1326              {
1327                std::string n = rld::to_string ((int) (a + 1));
1328                l = " " + generator_.arg_trace;
1329                l = rld::find_replace (l, "@ARG_NUM@", n);
1330                l = rld::find_replace (l, "@ARG_TYPE@", '"' + sig.args[a] + '"');
1331                l = rld::find_replace (l, "@ARG_SIZE@", "sizeof(" + sig.args[a] + ')');
1332                l = rld::find_replace (l, "@ARG_LABEL@", "a" + n);
1333                c.write_line(l);
1334              }
1335            }
1336
1337            l.clear ();
1338
1339            if (sig.has_ret ())
1340              l = " ret =";
1341
1342            l += " __real_" + sig.name + '(';
1343            if (sig.has_args ())
1344            {
1345              for (size_t a = 0; a < sig.args.size (); ++a)
1346              {
1347                if (a)
1348                  l += ", ";
1349                l += "a" + rld::to_string ((int) (a + 1));
1350              }
1351            }
1352            l += ");";
1353            c.write_line(l);
1354
1355            if (!generator_.lock_acquire.empty ())
1356              c.write_line(generator_.lock_acquire);
1357
1358            if (!generator_.exit_alloc.empty ())
1359            {
1360              l = " " + generator_.exit_alloc;
1361              macro_func_replace (l, sig, lss.str ());
1362              c.write_line(l);
1363            }
1364
1365            if (!generator_.lock_release.empty ())
1366              c.write_line(generator_.lock_release);
1367
1368            if (!generator_.exit_trace.empty ())
1369            {
1370              l = " " + generator_.exit_trace;
1371              macro_func_replace (l, sig, lss.str ());
1372              c.write_line(l);
1373            }
1374
1375            if (sig.has_ret () && !generator_.ret_trace.empty ())
1376            {
1377              std::string l = " " + generator_.ret_trace;
1378              l = rld::find_replace (l, "@RET_TYPE@", '"' + sig.ret + '"');
1379              l = rld::find_replace (l, "@RET_SIZE@", "sizeof(" + sig.ret + ')');
1380              l = rld::find_replace (l, "@RET_LABEL@", "ret");
1381              c.write_line(l);
1382              c.write_line(" return ret;");
1383            }
1384
1385            c.write_line("}");
1386          }
1387        }
1388
1389        if (!found)
1390          throw rld::error ("not found", "trace function: " + trace);
1391
1392        ++count;
1393      }
1394    }
1395
1396    void
1397    tracer::generate_bitmap (rld::process::tempfile& c,
1398                             const rld::strings&     names,
1399                             const std::string&      label,
1400                             const bool              global_set)
1401    {
1402      uint32_t bitmap_size = ((traces.size () - 1) / (4 * 8)) + 1;
1403
1404      std::stringstream ss;
1405
1406      ss << "uint32_t __rtld_trace_" << label << "_size = " << traces.size() << ";" << std::endl
1407         << "const uint32_t __rtld_trace_" << label << "[" << bitmap_size << "] = " << std::endl
1408         << "{" << std::endl;
1409
1410      size_t   count = 0;
1411      size_t   bit = 0;
1412      uint32_t bitmask = 0;
1413
1414      for (rld::strings::const_iterator ti = traces.begin ();
1415           ti != traces.end ();
1416           ++ti)
1417      {
1418        const std::string& trace = *ti;
1419        bool               set = global_set;
1420        if (!global_set)
1421        {
1422          for (rld::strings::const_iterator ni = names.begin ();
1423               ni != names.end ();
1424               ++ni)
1425          {
1426            const std::string& name = *ni;
1427            if (trace == name)
1428              set = true;
1429          }
1430        }
1431        if (set)
1432          bitmask |= 1 << bit;
1433        ++bit;
1434        ++count;
1435        if ((bit >= 32) || (count >= traces.size ()))
1436        {
1437          ss << " 0x" << std::hex << std::setfill ('0') << std::setw (8) << bitmask << ',';
1438          if ((count % 4) == 0)
1439            ss << std::endl;
1440          bit = 0;
1441          bitmask = 0;
1442        }
1443      }
1444
1445      c.write_line (ss.str ());
1446
1447      c.write_line ("};");
1448    }
1449
1450    void
1451    tracer::macro_func_replace (std::string&      text,
1452                               const signature&   sig,
1453                               const std::string& index)
1454    {
1455      text = rld::find_replace (text, "@FUNC_NAME@", '"' + sig.name + '"');
1456      text = rld::find_replace (text, "@FUNC_INDEX@", index);
1457      text = rld::find_replace (text, "@FUNC_LABEL@", sig.name);
1458      text = rld::find_replace (text, "@FUNC_DATA_SIZE@", "FUNC_DATA_SIZE_" + sig.name);
1459      text = rld::find_replace (text, "@FUNC_DATA_ENTRY_SIZE@", "FUNC_DATA_ENTRY_SIZE_" + sig.name);
1460      text = rld::find_replace (text, "@FUNC_DATA_RET_SIZE@", "FUNC_DATA_RET_SIZE_" + sig.name);
1461    }
1462
1463    const rld::strings&
1464    tracer::get_traces () const
1465    {
1466      return traces;
1467    }
1468
1469    void
1470    tracer::dump (std::ostream& out) const
1471    {
1472      out << " Tracer: " << name << std::endl
1473          << "  Traces: " << traces.size () << std::endl;
1474      for (rld::strings::const_iterator ti = traces.begin ();
1475           ti != traces.end ();
1476           ++ti)
1477      {
1478        out << "   " << (*ti) << std::endl;
1479      }
1480      out << "  Functions: " << functions_.size () << std::endl;
1481      for (functions::const_iterator fi = functions_.begin ();
1482           fi != functions_.end ();
1483           ++fi)
1484      {
1485        (*fi).dump (out);
1486      }
1487      out << "  Generator: " << std::endl;
1488      generator_.dump (out);
1489    }
1490
1491    linker::linker ()
1492    {
1493    }
1494
1495    void
1496    linker::load_config (const std::string& name,
1497                         const std::string& trace,
1498                         const std::string& path)
1499    {
1500      std::string sp = get_prefix ();
1501
1502      rld::path::path_join (sp, "share", sp);
1503      rld::path::path_join (sp, "rtems", sp);
1504      rld::path::path_join (sp, "trace-linker", sp);
1505
1506      if (!path.empty ())
1507        sp = path + ':' + sp;
1508
1509      if (rld::verbose ())
1510        std::cout << "search path: " << sp << std::endl;
1511
1512      config.set_search_path (sp);
1513      config.clear ();
1514      config.load (name);
1515      tracer_.load (config, trace);
1516    }
1517
1518    void
1519    linker::generate_wrapper (rld::process::tempfile& c)
1520    {
1521      tracer_.generate (c);
1522    }
1523
1524    void
1525    linker::compile_wrapper (rld::process::tempfile& c,
1526                             rld::process::tempfile& o)
1527    {
1528     rld::process::arg_container args;
1529
1530      if (rld::verbose ())
1531        std::cout << "wrapper O file: " << o.name () << std::endl;
1532
1533      rld::cc::make_cc_command (args);
1534      rld::cc::append_flags (rld::cc::ft_cflags, args);
1535
1536      args.push_back ("-O2");
1537      args.push_back ("-g");
1538      args.push_back ("-c");
1539      args.push_back ("-o");
1540      args.push_back (o.name ());
1541      args.push_back (c.name ());
1542
1543      rld::process::tempfile out;
1544      rld::process::tempfile err;
1545      rld::process::status   status;
1546
1547      status = rld::process::execute (rld::cc::get_cc (),
1548                                      args,
1549                                      out.name (),
1550                                      err.name ());
1551
1552      if ((status.type != rld::process::status::normal) ||
1553          (status.code != 0))
1554      {
1555        err.output (rld::cc::get_cc (), std::cout);
1556        if (dump_on_error)
1557          dump (std::cout);
1558        throw rld::error ("Compiler error", "compiling wrapper");
1559      }
1560    }
1561
1562    void
1563    linker::link (rld::process::tempfile& o,
1564                  const std::string&      ld_cmd)
1565    {
1566     rld::process::arg_container args;
1567
1568      if (rld::verbose ())
1569        std::cout << "linking: " << o.name () << std::endl;
1570
1571      std::string wrap = " -Wl,--wrap=";
1572
1573      rld::cc::make_ld_command (args);
1574
1575      rld::process::args_append (args,
1576                                 wrap + rld::join (tracer_.get_traces (), wrap));
1577      args.push_back (o.name ());
1578      rld::process::args_append (args, ld_cmd);
1579
1580      rld::process::tempfile out;
1581      rld::process::tempfile err;
1582      rld::process::status   status;
1583
1584      status = rld::process::execute (rld::cc::get_ld (),
1585                                      args,
1586                                      out.name (),
1587                                      err.name ());
1588
1589      if ((status.type != rld::process::status::normal) ||
1590          (status.code != 0))
1591      {
1592        err.output (rld::cc::get_ld (), std::cout);
1593        throw rld::error ("Linker error", "linking");
1594      }
1595      err.output (rld::cc::get_ld (), std::cout);
1596    }
1597
1598    void
1599    linker::dump (std::ostream& out) const
1600    {
1601      const rld::config::paths& cpaths = config.get_paths ();
1602      out << " Configuration Files: " << cpaths.size () << std::endl;
1603      for (rld::config::paths::const_iterator pi = cpaths.begin ();
1604           pi != cpaths.end ();
1605           ++pi)
1606      {
1607        out << "  " << (*pi) << std::endl;
1608      }
1609
1610      tracer_.dump (out);
1611    }
1612  }
1613}
1614
1615/**
1616 * RTEMS Trace Linker options. This needs to be rewritten to be like cc where
1617 * only a single '-' and long options is present. Anything after '--' is passed
1618 * to RTEMS's real linker.
1619 */
1620static struct option rld_opts[] = {
1621  { "help",        no_argument,            NULL,           'h' },
1622  { "version",     no_argument,            NULL,           'V' },
1623  { "verbose",     no_argument,            NULL,           'v' },
1624  { "warn",        no_argument,            NULL,           'w' },
1625  { "keep",        no_argument,            NULL,           'k' },
1626  { "compiler",    required_argument,      NULL,           'c' },
1627  { "linker",      required_argument,      NULL,           'l' },
1628  { "exec-prefix", required_argument,      NULL,           'E' },
1629  { "cflags",      required_argument,      NULL,           'f' },
1630  { "rtems",       required_argument,      NULL,           'r' },
1631  { "rtems-bsp",   required_argument,      NULL,           'B' },
1632  { "config",      required_argument,      NULL,           'C' },
1633  { "path",        required_argument,      NULL,           'P' },
1634  { "wrapper",     required_argument,      NULL,           'W' },
1635  { NULL,          0,                      NULL,            0 }
1636};
1637
1638void
1639usage (int exit_code)
1640{
1641  std::cout << "rtems-trace-ld [options] objects" << std::endl
1642            << "Options and arguments:" << std::endl
1643            << " -h          : help (also --help)" << std::endl
1644            << " -V          : print linker version number and exit (also --version)" << std::endl
1645            << " -v          : verbose (trace import parts), can supply multiple times" << std::endl
1646            << "               to increase verbosity (also --verbose)" << std::endl
1647            << " -w          : generate warnings (also --warn)" << std::endl
1648            << " -k          : keep temporary files (also --keep)" << std::endl
1649            << " -c compiler : target compiler is not standard (also --compiler)" << std::endl
1650            << " -l linker   : target linker is not standard (also --linker)" << std::endl
1651            << " -E prefix   : the RTEMS tool prefix (also --exec-prefix)" << std::endl
1652            << " -f cflags   : C compiler flags (also --cflags)" << std::endl
1653            << " -r path     : RTEMS path (also --rtems)" << std::endl
1654            << " -B bsp      : RTEMS arch/bsp (also --rtems-bsp)" << std::endl
1655            << " -W wrapper  : wrapper file name without ext (also --wrapper)" << std::endl
1656            << " -C ini      : user configuration INI file (also --config)" << std::endl
1657            << " -P path     : user configuration file search path (also --path)" << std::endl;
1658  ::exit (exit_code);
1659}
1660
1661static void
1662fatal_signal (int signum)
1663{
1664  signal (signum, SIG_DFL);
1665
1666  rld::process::temporaries_clean_up ();
1667
1668  /*
1669   * Get the same signal again, this time not handled, so its normal effect
1670   * occurs.
1671   */
1672  kill (getpid (), signum);
1673}
1674
1675static void
1676setup_signals (void)
1677{
1678  if (signal (SIGINT, SIG_IGN) != SIG_IGN)
1679    signal (SIGINT, fatal_signal);
1680#ifdef SIGHUP
1681  if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
1682    signal (SIGHUP, fatal_signal);
1683#endif
1684  if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
1685    signal (SIGTERM, fatal_signal);
1686#ifdef SIGPIPE
1687  if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
1688    signal (SIGPIPE, fatal_signal);
1689#endif
1690#ifdef SIGCHLD
1691  signal (SIGCHLD, SIG_DFL);
1692#endif
1693}
1694
1695int
1696main (int argc, char* argv[])
1697{
1698  int ec = 0;
1699
1700  setup_signals ();
1701
1702  try
1703  {
1704    rld::trace::linker linker;
1705    std::string        cc;
1706    std::string        ld;
1707    std::string        ld_cmd;
1708    std::string        configuration;
1709    std::string        path;
1710    std::string        trace = "tracer";
1711    std::string        wrapper;
1712    std::string        rtems_path;
1713    std::string        rtems_arch_bsp;
1714
1715    rld::set_cmdline (argc, argv);
1716
1717    while (true)
1718    {
1719      int opt = ::getopt_long (argc, argv, "hvwkVc:l:E:f:C:P:r:B:W:", rld_opts, NULL);
1720      if (opt < 0)
1721        break;
1722
1723      switch (opt)
1724      {
1725        case 'V':
1726          std::cout << "rtems-trace-ld (RTEMS Trace Linker) " << rld::version ()
1727                    << std::endl;
1728          ::exit (0);
1729          break;
1730
1731        case 'v':
1732          rld::verbose_inc ();
1733          break;
1734
1735        case 'w':
1736#if HAVE_WARNINGS
1737          warnings = true;
1738#endif
1739          break;
1740
1741        case 'k':
1742          rld::process::set_keep_temporary_files ();
1743          break;
1744
1745        case 'c':
1746          cc = optarg;
1747          break;
1748
1749        case 'l':
1750          ld = optarg;
1751          break;
1752
1753        case 'E':
1754          rld::cc::set_exec_prefix (optarg);
1755          break;
1756
1757        case 'f':
1758          rld::cc::append_flags (optarg, rld::cc::ft_cflags);
1759          break;
1760
1761        case 'r':
1762          rtems_path = optarg;
1763          break;
1764
1765        case 'B':
1766          rtems_arch_bsp = optarg;
1767          break;
1768
1769        case 'C':
1770          configuration = optarg;
1771          break;
1772
1773        case 'P':
1774          if (!path.empty ())
1775            path += ":";
1776          path += optarg;
1777          break;
1778
1779        case 'W':
1780          wrapper = optarg;
1781          break;
1782
1783        case '?':
1784          usage (3);
1785          break;
1786
1787        case 'h':
1788          usage (0);
1789          break;
1790      }
1791    }
1792
1793    /*
1794     * Set the program name.
1795     */
1796    rld::set_progname (argv[0]);
1797
1798    argc -= optind;
1799    argv += optind;
1800
1801    if (rld::verbose ())
1802    {
1803      std::cout << "RTEMS Trace Linker " << rld::version () << std::endl;
1804      std::cout << " " << rld::get_cmdline () << std::endl;
1805    }
1806
1807    /*
1808     * Load the arch/bsp value if provided.
1809     */
1810    if (!rtems_arch_bsp.empty ())
1811    {
1812      const std::string& prefix = rld::get_prefix ();
1813      if (rtems_path.empty () && prefix.empty ())
1814        throw rld::error ("No RTEMS path provided with arch/bsp", "options");
1815      if (!rtems_path.empty ())
1816        rld::rtems::set_path (rtems_path);
1817      else
1818        rld::rtems::set_path (prefix);
1819      rld::rtems::set_arch_bsp (rtems_arch_bsp);
1820    }
1821
1822    /**
1823     * Set the compiler and/or linker if provided.
1824     */
1825    if (!cc.empty ())
1826      rld::cc::set_cc (cc);
1827    if (!ld.empty ())
1828      rld::cc::set_ld (ld);
1829
1830    /*
1831     * Load the remaining command line arguments into the linker command line.
1832     */
1833    while (argc--)
1834    {
1835      /*
1836       * Create this value because 'ld_cmd += ' ' + *argv++' fails on clang.
1837       */
1838      std::string av = *argv++;
1839      ld_cmd += ' ' + av;
1840    }
1841    ld_cmd = rld::trim (ld_cmd);
1842
1843    /*
1844     * If there are no object files there is nothing to link.
1845     */
1846    if (ld_cmd.empty ())
1847      throw rld::error ("no trace linker options", "options");
1848
1849    /*
1850     * Perform a trace link.
1851     */
1852    try
1853    {
1854      linker.load_config (configuration, trace, path);
1855
1856      rld::process::tempfile c (".c");
1857      rld::process::tempfile o (".o");
1858
1859      if (!wrapper.empty ())
1860      {
1861        c.override (wrapper);
1862        c.keep ();
1863        o.override (wrapper);
1864        o.keep ();
1865      }
1866
1867      linker.generate_wrapper (c);
1868      linker.compile_wrapper (c, o);
1869      linker.link (o, ld_cmd);
1870
1871      if (rld::verbose ())
1872        linker.dump (std::cout);
1873    }
1874    catch (...)
1875    {
1876      throw;
1877    }
1878
1879  }
1880  catch (rld::error re)
1881  {
1882    std::cerr << "error: "
1883              << re.where << ": " << re.what
1884              << std::endl;
1885    ec = 10;
1886  }
1887  catch (std::exception e)
1888  {
1889    int   status;
1890    char* realname;
1891    realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
1892    std::cerr << "error: exception: " << realname << " [";
1893    ::free (realname);
1894    const std::type_info &ti = typeid (e);
1895    realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
1896    std::cerr << realname << "] " << e.what () << std::endl;
1897    ::free (realname);
1898    ec = 11;
1899  }
1900  catch (...)
1901  {
1902    /*
1903     * Helps to know if this happens.
1904     */
1905    std::cout << "error: unhandled exception" << std::endl;
1906    ec = 12;
1907  }
1908
1909  return ec;
1910}
Note: See TracBrowser for help on using the repository browser.