source: rtems-tools/linkers/rtems-tld.cpp @ 1318c11

5
Last change on this file since 1318c11 was efc4f09, checked in by Chris Johns <chrisj@…>, on 12/09/15 at 09:08:19

Add release versioning support.

Support a top level VERSION file that defines an RTEMS release.

Fix the install of the python modules including thertems-test.

Update the git python module to the RSB version. Fix the options to
not call clean and to call dirty.

Update the version python module.

Fix the rtld C++ support to the VERSION file and the top level waf
script.

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