source: rtems-tools/linkers/rtems-tld.cpp @ b249516

4.104.115
Last change on this file since b249516 was b249516, checked in by Chris Johns <chrisj@…>, on 03/29/15 at 07:06:00

rtemstoolkit: Add support to return the system path split as paths.

Seacch the path for the program name if not found and set it as
an absolute path. This allow the prefix to be found.

  • 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 = rld::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.