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

4.104.11
Last change on this file since d499e6d was d499e6d, checked in by Chris Johns <chrisj@…>, on Mar 27, 2015 at 9:21:33 AM

trace-linker: Add the trace function signatures to the wrapper code.

This gives the tools the ability to extract all needed data from the
executable.

  • Property mode set to 100644
File size: 55.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_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 sorted list
617       *                    of trace functions by teh trace linker. It can be
618       *                    used to index the `names`, `enables` and `triggers`
619       *                    data.
620       * # @FUNC_LABEL@     The trace function name as a C label that can be
621       *                     referenced. You can take the address of the label.
622       * # @FUNC_DATA_SIZE@ The size of the daya in bytes.
623       * # @ARG_NUM@        The argument number to the trace function.
624       * # @ARG_TYPE@       The type of the argument as a C string.
625       * # @ARG_SIZE@       The size of the type of the argument in bytes.
626       * # @ARG_LABEL@      The argument as a C label that can be referenced.
627       * # @RET_TYPE@       The type of the return value as a C string.
628       * # @RET_SIZE@       The size of the type of the return value in bytes.
629       * # @RET_LABEL@      The retrun value as a C label that can be referenced.
630       *
631       * The `buffer-alloc`, `entry-trace` and `exit-trace` can be transformed using
632       *  the following  macros:
633       *
634       * # @FUNC_NAME@
635       * # @FUNC_INDEX@
636       * # @FUNC_LABEL@
637       * # @FUNC_DATA_SZIE@
638       *
639       * The `arg-trace` can be transformed using the following macros:
640       *
641       * # @ARG_NUM@
642       * # @ARG_TYPE@
643       * # @ARG_SIZE@
644       * # @ARG_LABEL@
645       *
646       * The `ret-trace` can be transformed using the following macros:
647       *
648       * # @RET_TYPE@
649       * # @RET_SIZE@
650       * # @RET_LABEL@
651       *
652       * @note The quoting and list spliting is a little weak because a delimiter
653       *       in a quote should not be seen as a delimiter.
654       */
655      const rld::config::section& section = config.get_section (name);
656
657      config.includes (section);
658
659      parse (config, section, "headers",     "header", headers);
660      parse (config, section, "defines",     "define", defines);
661      parse (config, section, "code-blocks", "code",   code, false);
662
663      if (section.has_record ("lock-local"))
664        lock_local = rld::dequote (section.get_record_item ("lock-local"));
665      if (section.has_record ("lock-acquire"))
666        lock_acquire = rld::dequote (section.get_record_item ("lock-acquire"));
667      if (section.has_record ("lock-release"))
668        lock_release = rld::dequote (section.get_record_item ("lock-release"));
669      if (section.has_record ("buffer-local"))
670        buffer_local = rld::dequote (section.get_record_item ("buffer-local"));
671      if (section.has_record ("entry-trace"))
672        entry_trace = rld::dequote (section.get_record_item ("entry-trace"));
673      if (section.has_record ("entry-alloc"))
674        entry_alloc = rld::dequote (section.get_record_item ("entry-alloc"));
675      if (section.has_record ("arg-trace"))
676        arg_trace = rld::dequote (section.get_record_item ("arg-trace"));
677      if (section.has_record ("exit-trace"))
678        exit_trace = rld::dequote (section.get_record_item ("exit-trace"));
679      if (section.has_record ("exit-alloc"))
680        exit_alloc = rld::dequote (section.get_record_item ("exit-alloc"));
681      if (section.has_record ("ret-trace"))
682        ret_trace = rld::dequote (section.get_record_item ("ret-trace"));
683    }
684
685    void
686    generator::dump (std::ostream& out) const
687    {
688      out << "  Generator: " << name << std::endl
689          << "   Headers: " << headers.size () << std::endl;
690      for (rld::strings::const_iterator hi = headers.begin ();
691           hi != headers.end ();
692           ++hi)
693      {
694        out << "    " << (*hi) << std::endl;
695      }
696      out << "   Defines: " << defines.size () << std::endl;
697      for (rld::strings::const_iterator di = defines.begin ();
698           di != defines.end ();
699           ++di)
700      {
701        out << "    " << (*di) << std::endl;
702      }
703      out << "   Arg Trace Code: " << arg_trace << std::endl
704          << "   Return Trace Code: " << ret_trace << std::endl
705          << "   Code blocks: " << std::endl;
706      for (rld::strings::const_iterator ci = code.begin ();
707           ci != code.end ();
708           ++ci)
709      {
710        out << "      > "
711            << rld::find_replace (*ci, "\n", "\n      | ") << std::endl;
712      }
713    }
714
715    tracer::tracer ()
716    {
717    }
718
719    void
720    tracer::load (rld::config::config& config,
721                  const std::string&   tname)
722    {
723      /*
724       * The configuration must contain a "section" section. This is the top level
725       * configuration and may contain:
726       *
727       *  # name      The name of trace being linked.
728       *  # options   A list of option sections.
729       *  # defines   A list of sections containing defines or define record.
730       *  # define    A list of define string that are single or double quoted.
731       *  # enables   The list of sections containing enabled functions to trace.
732       *  # triggers  The list of sections containing enabled functions to trigger trace on.
733       *  # traces    The list of sections containing function lists to trace.
734       *  # functions The list of sections containing function details.
735       *  # include   The list of files to include.
736       *
737       * The following records are required:
738       *
739       *  # name
740       *  # traces
741       *  # functions
742       */
743      const rld::config::section& section = config.get_section (tname);
744
745      name = section.get_record_item ("name");
746      load_options (config, section);
747      config.includes (section);
748      load_defines (config, section);
749      load_functions (config, section);
750      load_enables (config, section);
751      load_triggers (config, section);
752      load_traces (config, section);
753    }
754
755    void
756    tracer::load_options (rld::config::config&        config,
757                          const rld::config::section& section)
758    {
759      rld::strings opts;
760      rld::config::parse_items (section, "options", opts, false, true, true);
761
762      if (rld::verbose ())
763        std::cout << "options: " << section.name << ": " << opts.size () << std::endl;
764
765      options_.clear ();
766
767      for (rld::strings::const_iterator osi = opts.begin ();
768           osi != opts.end ();
769           ++osi)
770      {
771        const rld::config::section& osec = config.get_section (*osi);
772
773        if (rld::verbose ())
774          std::cout << " options: " << osec.name
775                    << ": recs:" << osec.recs.size () << std::endl;
776
777        for (rld::config::records::const_iterator ori = osec.recs.begin ();
778             ori != osec.recs.end ();
779             ++ori)
780        {
781          const rld::config::record& opt = *ori;
782
783          if (!opt.single ())
784              throw rld::error ("mode than one option specified", "option: " + opt.name);
785
786          options_.push_back (option (opt.name, opt[0]));
787
788          if (opt.name == "dump-on-error")
789          {
790            dump_on_error = true;
791          }
792          else if (opt.name == "verbose")
793          {
794            int level = ::strtoul(opt[0].c_str (), 0, 0);
795            if (level == 0)
796              level = 1;
797            for (int l = 0; l < level; ++l)
798              rld::verbose_inc ();
799          }
800          else if (opt.name == "prefix")
801          {
802            rld::cc::set_exec_prefix (opt[0]);
803          }
804          else if (opt.name == "cc")
805          {
806            rld::cc::set_cc (opt[0]);
807          }
808          else if (opt.name == "ld")
809          {
810            rld::cc::set_ld (opt[0]);
811          }
812          else if (opt.name == "cflags")
813          {
814            rld::cc::append_flags (opt[0], rld::cc::ft_cflags);
815          }
816          else if (opt.name == "rtems-path")
817          {
818            rld::rtems::set_path(opt[0]);
819          }
820          else if (opt.name == "rtems-bsp")
821          {
822            rld::rtems::set_arch_bsp(opt[0]);
823          }
824        }
825      }
826    }
827
828    void
829    tracer::load_defines (rld::config::config&        config,
830                          const rld::config::section& section)
831    {
832      parse (config, section, "defines", "define", defines);
833    }
834
835    void
836    tracer::load_functions (rld::config::config&        config,
837                            const rld::config::section& section)
838    {
839      rld::strings fl;
840      rld::config::parse_items (section, "functions", fl, true);
841      for (rld::strings::const_iterator fli = fl.begin ();
842           fli != fl.end ();
843           ++fli)
844      {
845        functions_.push_back (function (config, *fli));
846      }
847    }
848
849    void
850    tracer::load_enables (rld::config::config&        config,
851                          const rld::config::section& section)
852    {
853      parse (config, section, "enables", "enable", enables);
854    }
855
856    void
857    tracer::load_triggers (rld::config::config&        config,
858                           const rld::config::section& section)
859    {
860      parse (config, section, "triggers", "trigger", triggers);
861    }
862
863    void
864    tracer::load_traces (rld::config::config&        config,
865                         const rld::config::section& section)
866    {
867      parse (config, section, "traces", "trace", traces);
868
869      rld::strings gens;
870      std::string  gen;
871
872      parse (config, section, "traces", "generator", gens);
873
874      if (gens.size () > 1)
875      {
876        if (dump_on_error)
877          dump (std::cout);
878        throw rld::error ("duplicate generators", "tracer: " + section.name);
879      }
880
881      if (gens.size () == 0)
882      {
883        const rld::config::section& dg_section = config.get_section ("default-generator");
884        gen = dg_section.get_record_item ("generator");
885        config.includes (dg_section);
886      }
887      else
888      {
889        gen = gens[0];
890      }
891
892      sort (traces.begin (), traces.end ());
893
894      generator_ = generator (config, gen);
895    }
896
897    const std::string
898    tracer::get_option (const std::string& name) const
899    {
900      std::string value;
901      for (options::const_iterator oi = options_.begin ();
902           oi != options_.end ();
903           ++oi)
904      {
905        const option& opt = *oi;
906        if (opt.name == name)
907        {
908          value = opt.value;
909          break;
910        }
911      }
912      return value;
913    }
914
915    void
916    tracer::generate (rld::process::tempfile& c)
917    {
918      c.open (true);
919
920      if (rld::verbose ())
921        std::cout << "wrapper C file: " << c.name () << std::endl;
922
923      try
924      {
925        c.write_line ("/*");
926        c.write_line (" * RTEMS Trace Linker Wrapper");
927        c.write_line (" *  Automatically generated.");
928        c.write_line (" */");
929
930        c.write_line ("");
931        c.write_line ("/*");
932        c.write_line (" * Tracer: " + name);
933        c.write_line (" */");
934        c.write_lines (defines);
935
936        c.write_line ("");
937        c.write_line ("/*");
938        c.write_line (" * Generator: " + generator_.name);
939        c.write_line (" */");
940        c.write_lines (generator_.defines);
941        c.write_lines (generator_.headers);
942        c.write_line ("");
943        generate_functions (c);
944        generate_names (c);
945        generate_signatures (c);
946        generate_enables (c);
947        generate_triggers (c);
948        c.write_line ("");
949        c.write_lines (generator_.code);
950
951        generate_traces (c);
952      }
953      catch (...)
954      {
955        c.close ();
956        if (dump_on_error)
957          dump (std::cout);
958        throw;
959      }
960
961      c.close ();
962
963      if (rld::verbose (RLD_VERBOSE_DETAILS))
964      {
965        std::cout << "Generated C file:" << std::endl;
966        c.output (" ", std::cout, true);
967      }
968    }
969
970    void
971    tracer::generate_names (rld::process::tempfile& c)
972    {
973      const std::string opt = get_option ("gen-names");
974
975      if (opt == "disable")
976        return;
977
978      c.write_line ("");
979      c.write_line ("/*");
980      c.write_line (" * Names.");
981      c.write_line (" */");
982
983      std::stringstream sss;
984      sss << "uint32_t __rtld_trace_names_size = " << traces.size() << ";" << std::endl
985          << "const char const* __rtld_trace_names[" << traces.size() << "] = " << std::endl
986          << "{";
987      c.write_line (sss.str ());
988
989      int count = 0;
990
991      for (rld::strings::const_iterator ti = traces.begin ();
992           ti != traces.end ();
993           ++ti)
994      {
995        const std::string& trace = *ti;
996        sss.str (std::string ());
997        sss << "  /* " << std::setw (3) << count << " */ \"" << trace << "\",";
998        c.write_line (sss.str ());
999        ++count;
1000      }
1001
1002      c.write_line ("};");
1003    }
1004
1005    void
1006    tracer::generate_signatures (rld::process::tempfile& c)
1007    {
1008      const std::string opt = get_option ("gen-sigs");
1009
1010      if (opt == "disable")
1011        return;
1012
1013      c.write_line ("");
1014      c.write_line ("/*");
1015      c.write_line (" * Signatures.");
1016      c.write_line (" */");
1017      c.write_line ("");
1018      c.write_line ("typedef struct {");
1019      c.write_line (" uint32_t          size;");
1020      c.write_line (" const char* const type;");
1021      c.write_line ("} __rtld_sig_arg;");
1022      c.write_line ("");
1023      c.write_line ("typedef struct {");
1024      c.write_line (" uint32_t              argc;");
1025      c.write_line (" const __rtld_sig_arg* args;");
1026      c.write_line ("} __rtld_sig;");
1027      c.write_line ("");
1028
1029      std::stringstream sss;
1030
1031      for (rld::strings::const_iterator ti = traces.begin ();
1032           ti != traces.end ();
1033           ++ti)
1034      {
1035        const std::string& trace = *ti;
1036        bool               found = false;
1037
1038        for (functions::const_iterator fi = functions_.begin ();
1039             !found && (fi != functions_.end ());
1040             ++fi)
1041        {
1042          const function&            funcs = *fi;
1043          signatures::const_iterator si = funcs.signatures_.find (trace);
1044
1045          if (si != funcs.signatures_.end ())
1046          {
1047            found = true;
1048
1049            const signature& sig = (*si).second;
1050
1051            size_t argc = 1 + (sig.args.size () == 0 ? 1 : sig.args.size ());
1052
1053            sss.str (std::string ());
1054
1055            sss << "const __rtld_sig_arg __rtld_sig_args_" << trace
1056                << "[" << argc << "] =" << std::endl
1057                << "{" << std::endl;
1058
1059            if (sig.has_ret ())
1060              sss << "  { sizeof (" << sig.ret << "), \"" << sig.ret << "\" }," << std::endl;
1061            else
1062              sss << "  { 0, \"void\" }," << std::endl;
1063
1064            if (sig.has_args ())
1065            {
1066              for (size_t a = 0; a < sig.args.size (); ++a)
1067              {
1068                sss << "  { sizeof (" << sig.args[a] << "), \"" << sig.args[a] << "\" },"
1069                    << std::endl;
1070              }
1071            }
1072            else
1073              sss << "  { 0, \"void\" }," << std::endl;
1074
1075            sss << "};" << std::endl;
1076
1077            c.write_line (sss.str ());
1078          }
1079        }
1080
1081        if (!found)
1082          throw rld::error ("not found", "trace function: " + trace);
1083      }
1084
1085      sss.str (std::string ());
1086
1087      sss << "const __rtld_sig __rtld_signatures[" << traces.size () << "] = "
1088          << "{" << std::endl;
1089
1090      for (rld::strings::const_iterator ti = traces.begin ();
1091           ti != traces.end ();
1092           ++ti)
1093      {
1094        const std::string& trace = *ti;
1095
1096        for (functions::const_iterator fi = functions_.begin ();
1097             fi != functions_.end ();
1098             ++fi)
1099        {
1100          const function&            funcs = *fi;
1101          signatures::const_iterator si = funcs.signatures_.find (trace);
1102
1103          if (si != funcs.signatures_.end ())
1104          {
1105            const signature& sig = (*si).second;
1106            size_t argc = 1 + (sig.args.size () == 0 ? 1 : sig.args.size ());
1107            sss << "  { " << argc << ", __rtld_sig_args_" << trace << " }," << std::endl;
1108          }
1109
1110          break;
1111        }
1112      }
1113
1114      sss << "};" << std::endl;
1115
1116      c.write_line (sss.str ());
1117    }
1118
1119    void
1120    tracer::generate_enables (rld::process::tempfile& c)
1121    {
1122      const std::string opt = get_option ("gen-enables");
1123      bool              global_state = false;
1124
1125      if (opt == "disable")
1126        return;
1127
1128      if (opt == "global-on")
1129        global_state = true;
1130
1131      c.write_line ("");
1132      c.write_line ("/*");
1133      c.write_line (" * Enables.");
1134      c.write_line (" */");
1135
1136      generate_bitmap (c, enables, "enables", global_state);
1137    }
1138
1139    void
1140    tracer::generate_triggers (rld::process::tempfile& c)
1141    {
1142      const std::string opt = get_option ("gen-triggers");
1143      bool              global_state = false;
1144
1145      if (opt == "disable")
1146        return;
1147
1148      if (opt == "global-on")
1149        global_state = true;
1150
1151      c.write_line ("");
1152      c.write_line ("/*");
1153      c.write_line (" * Triggers.");
1154      c.write_line (" */");
1155
1156      generate_bitmap (c, triggers, "triggers", global_state);
1157
1158      c.write_line ("");
1159    }
1160
1161    void
1162    tracer::generate_functions (rld::process::tempfile& c)
1163    {
1164      c.write_line ("/*");
1165      c.write_line (" * Functions.");
1166      c.write_line (" */");
1167
1168      for (functions::const_iterator fi = functions_.begin ();
1169           fi != functions_.end ();
1170           ++fi)
1171      {
1172        const function& funcs = *fi;
1173
1174        for (rld::strings::const_iterator ti = traces.begin ();
1175             ti != traces.end ();
1176             ++ti)
1177        {
1178          const std::string&         trace = *ti;
1179          signatures::const_iterator si = funcs.signatures_.find (trace);
1180
1181          if (si != funcs.signatures_.end ())
1182          {
1183            c.write_line ("");
1184            c.write_line ("/*");
1185            c.write_line (" * Function: " + funcs.name);
1186            c.write_line (" */");
1187            c.write_lines (funcs.defines);
1188            c.write_lines (funcs.headers);
1189            break;
1190          }
1191        }
1192      }
1193    }
1194
1195    void
1196    tracer::generate_traces (rld::process::tempfile& c)
1197    {
1198      c.write_line ("/*");
1199      c.write_line (" * Wrappers.");
1200      c.write_line (" */");
1201
1202      size_t count = 0;
1203
1204      for (rld::strings::const_iterator ti = traces.begin ();
1205           ti != traces.end ();
1206           ++ti)
1207      {
1208        const std::string& trace = *ti;
1209        bool               found = false;
1210
1211        for (functions::const_iterator fi = functions_.begin ();
1212             fi != functions_.end ();
1213             ++fi)
1214        {
1215          const function&            funcs = *fi;
1216          signatures::const_iterator si = funcs.signatures_.find (trace);
1217
1218          if (si != funcs.signatures_.end ())
1219          {
1220            found = true;
1221
1222            const signature& sig = (*si).second;
1223
1224            std::stringstream lss;
1225            lss << count;
1226
1227            c.write_line("");
1228
1229            if (sig.has_args () || (sig.has_ret () && !generator_.ret_trace.empty ()))
1230            {
1231              std::string ds;
1232              std::string des;
1233              std::string drs;
1234              bool        ds_added = false;
1235              bool        des_added = false;
1236              bool        drs_added = false;
1237              ds  = "#define FUNC_DATA_SIZE_" + sig.name + " (";
1238              des = "#define FUNC_DATA_ENTRY_SIZE_" + sig.name + " (";
1239              drs = "#define FUNC_DATA_RET_SIZE_" + sig.name + " (";
1240              if (sig.has_args ())
1241              {
1242                for (size_t a = 0; a < sig.args.size (); ++a)
1243                {
1244                  if (ds_added)
1245                    ds += " + ";
1246                  else
1247                    ds_added = true;
1248                  if (des_added)
1249                    des += " + ";
1250                  else
1251                    des_added = true;
1252                  ds += "sizeof(" + sig.args[a] + ')';
1253                  des += "sizeof(" + sig.args[a] + ')';
1254                }
1255              }
1256              if (sig.has_ret () && !generator_.ret_trace.empty ())
1257              {
1258                if (ds_added)
1259                  ds += " + ";
1260                else
1261                  ds_added = true;
1262                if (drs_added)
1263                  drs += " + ";
1264                else
1265                  drs_added = true;
1266                ds += "sizeof(" + sig.ret + ')';
1267                drs += "sizeof(" + sig.ret + ')';
1268              }
1269              if (!ds_added)
1270                ds += '0';
1271              ds += ')';
1272              if (!des_added)
1273                des += '0';
1274              des += ')';
1275              if (!drs_added)
1276                drs += '0';
1277              drs += ')';
1278              c.write_line(ds);
1279              c.write_line(des);
1280              c.write_line(drs);
1281            }
1282
1283            c.write_line(sig.decl () + ";");
1284            c.write_line(sig.decl ("__real_") + ";");
1285            c.write_line(sig.decl ("__wrap_"));
1286            c.write_line("{");
1287
1288            if (!generator_.lock_local.empty ())
1289              c.write_line(generator_.lock_local);
1290
1291            if (!generator_.buffer_local.empty ())
1292              c.write_line(generator_.buffer_local);
1293
1294            if (sig.has_ret ())
1295              c.write_line(" " + sig.ret + " ret;");
1296
1297            std::string l;
1298
1299            if (!generator_.lock_acquire.empty ())
1300              c.write_line(generator_.lock_acquire);
1301
1302            if (!generator_.entry_alloc.empty ())
1303            {
1304              l = " " + generator_.entry_alloc;
1305              macro_func_replace (l, sig, lss.str ());
1306              c.write_line(l);
1307            }
1308
1309            if (!generator_.lock_release.empty ())
1310              c.write_line(generator_.lock_release);
1311
1312            if (!generator_.entry_trace.empty ())
1313            {
1314              l = " " + generator_.entry_trace;
1315              macro_func_replace (l, sig, lss.str ());
1316              c.write_line(l);
1317            }
1318
1319            if (sig.has_args ())
1320            {
1321              for (size_t a = 0; a < sig.args.size (); ++a)
1322              {
1323                std::string n = rld::to_string ((int) (a + 1));
1324                l = " " + generator_.arg_trace;
1325                l = rld::find_replace (l, "@ARG_NUM@", n);
1326                l = rld::find_replace (l, "@ARG_TYPE@", '"' + sig.args[a] + '"');
1327                l = rld::find_replace (l, "@ARG_SIZE@", "sizeof(" + sig.args[a] + ')');
1328                l = rld::find_replace (l, "@ARG_LABEL@", "a" + n);
1329                c.write_line(l);
1330              }
1331            }
1332
1333            l.clear ();
1334
1335            if (sig.has_ret ())
1336              l = " ret =";
1337
1338            l += " __real_" + sig.name + '(';
1339            if (sig.has_args ())
1340            {
1341              for (size_t a = 0; a < sig.args.size (); ++a)
1342              {
1343                if (a)
1344                  l += ", ";
1345                l += "a" + rld::to_string ((int) (a + 1));
1346              }
1347            }
1348            l += ");";
1349            c.write_line(l);
1350
1351            if (!generator_.lock_acquire.empty ())
1352              c.write_line(generator_.lock_acquire);
1353
1354            if (!generator_.exit_alloc.empty ())
1355            {
1356              l = " " + generator_.exit_alloc;
1357              macro_func_replace (l, sig, lss.str ());
1358              c.write_line(l);
1359            }
1360
1361            if (!generator_.lock_release.empty ())
1362              c.write_line(generator_.lock_release);
1363
1364            if (!generator_.exit_trace.empty ())
1365            {
1366              l = " " + generator_.exit_trace;
1367              macro_func_replace (l, sig, lss.str ());
1368              c.write_line(l);
1369            }
1370
1371            if (sig.has_ret () && !generator_.ret_trace.empty ())
1372            {
1373              std::string l = " " + generator_.ret_trace;
1374              l = rld::find_replace (l, "@RET_TYPE@", '"' + sig.ret + '"');
1375              l = rld::find_replace (l, "@RET_SIZE@", "sizeof(" + sig.ret + ')');
1376              l = rld::find_replace (l, "@RET_LABEL@", "ret");
1377              c.write_line(l);
1378              c.write_line(" return ret;");
1379            }
1380
1381            c.write_line("}");
1382          }
1383        }
1384
1385        if (!found)
1386          throw rld::error ("not found", "trace function: " + trace);
1387
1388        ++count;
1389      }
1390    }
1391
1392    void
1393    tracer::generate_bitmap (rld::process::tempfile& c,
1394                             const rld::strings&     names,
1395                             const std::string&      label,
1396                             const bool              global_set)
1397    {
1398      uint32_t bitmap_size = ((traces.size () - 1) / (4 * 8)) + 1;
1399
1400      std::stringstream ss;
1401
1402      ss << "uint32_t __rtld_trace_" << label << "_size = " << traces.size() << ";" << std::endl
1403         << "const uint32_t __rtld_trace_" << label << "[" << bitmap_size << "] = " << std::endl
1404         << "{" << std::endl;
1405
1406      size_t   count = 0;
1407      size_t   bit = 0;
1408      uint32_t bitmask = 0;
1409
1410      for (rld::strings::const_iterator ti = traces.begin ();
1411           ti != traces.end ();
1412           ++ti)
1413      {
1414        const std::string& trace = *ti;
1415        bool               set = global_set;
1416        if (!global_set)
1417        {
1418          for (rld::strings::const_iterator ni = names.begin ();
1419               ni != names.end ();
1420               ++ni)
1421          {
1422            const std::string& name = *ni;
1423            if (trace == name)
1424              set = true;
1425          }
1426        }
1427        if (set)
1428          bitmask |= 1 << bit;
1429        ++bit;
1430        ++count;
1431        if ((bit >= 32) || (count >= traces.size ()))
1432        {
1433          ss << " 0x" << std::hex << std::setfill ('0') << std::setw (8) << bitmask << ',';
1434          if ((count % 4) == 0)
1435            ss << std::endl;
1436          bit = 0;
1437          bitmask = 0;
1438        }
1439      }
1440
1441      c.write_line (ss.str ());
1442
1443      c.write_line ("};");
1444    }
1445
1446    void
1447    tracer::macro_func_replace (std::string&      text,
1448                               const signature&   sig,
1449                               const std::string& index)
1450    {
1451      text = rld::find_replace (text, "@FUNC_NAME@", '"' + sig.name + '"');
1452      text = rld::find_replace (text, "@FUNC_INDEX@", index);
1453      text = rld::find_replace (text, "@FUNC_LABEL@", sig.name);
1454      text = rld::find_replace (text, "@FUNC_DATA_SIZE@", "FUNC_DATA_SIZE_" + sig.name);
1455      text = rld::find_replace (text, "@FUNC_DATA_ENTRY_SIZE@", "FUNC_DATA_ENTRY_SIZE_" + sig.name);
1456      text = rld::find_replace (text, "@FUNC_DATA_RET_SIZE@", "FUNC_DATA_RET_SIZE_" + sig.name);
1457    }
1458
1459    const rld::strings&
1460    tracer::get_traces () const
1461    {
1462      return traces;
1463    }
1464
1465    void
1466    tracer::dump (std::ostream& out) const
1467    {
1468      out << " Tracer: " << name << std::endl
1469          << "  Traces: " << traces.size () << std::endl;
1470      for (rld::strings::const_iterator ti = traces.begin ();
1471           ti != traces.end ();
1472           ++ti)
1473      {
1474        out << "   " << (*ti) << std::endl;
1475      }
1476      out << "  Functions: " << functions_.size () << std::endl;
1477      for (functions::const_iterator fi = functions_.begin ();
1478           fi != functions_.end ();
1479           ++fi)
1480      {
1481        (*fi).dump (out);
1482      }
1483      out << "  Generator: " << std::endl;
1484      generator_.dump (out);
1485    }
1486
1487    linker::linker ()
1488    {
1489    }
1490
1491    void
1492    linker::load_config (const std::string& name,
1493                         const std::string& trace,
1494                         const std::string& path)
1495    {
1496      std::string sp = get_prefix ();
1497
1498      rld::path::path_join (sp, "share", sp);
1499      rld::path::path_join (sp, "rtems", sp);
1500      rld::path::path_join (sp, "trace-linker", sp);
1501
1502      if (!path.empty ())
1503        sp = path + ':' + sp;
1504
1505      if (rld::verbose ())
1506        std::cout << "search path: " << sp << std::endl;
1507
1508      config.set_search_path (sp);
1509      config.clear ();
1510      config.load (name);
1511      tracer_.load (config, trace);
1512    }
1513
1514    void
1515    linker::generate_wrapper (rld::process::tempfile& c)
1516    {
1517      tracer_.generate (c);
1518    }
1519
1520    void
1521    linker::compile_wrapper (rld::process::tempfile& c,
1522                             rld::process::tempfile& o)
1523    {
1524     rld::process::arg_container args;
1525
1526      if (rld::verbose ())
1527        std::cout << "wrapper O file: " << o.name () << std::endl;
1528
1529      rld::cc::make_cc_command (args);
1530      rld::cc::append_flags (rld::cc::ft_cflags, args);
1531
1532      args.push_back ("-O2");
1533      args.push_back ("-g");
1534      args.push_back ("-c");
1535      args.push_back ("-o");
1536      args.push_back (o.name ());
1537      args.push_back (c.name ());
1538
1539      rld::process::tempfile out;
1540      rld::process::tempfile err;
1541      rld::process::status   status;
1542
1543      status = rld::process::execute (rld::cc::get_cc (),
1544                                      args,
1545                                      out.name (),
1546                                      err.name ());
1547
1548      if ((status.type != rld::process::status::normal) ||
1549          (status.code != 0))
1550      {
1551        err.output (rld::cc::get_cc (), std::cout);
1552        if (dump_on_error)
1553          dump (std::cout);
1554        throw rld::error ("Compiler error", "compiling wrapper");
1555      }
1556    }
1557
1558    void
1559    linker::link (rld::process::tempfile& o,
1560                  const std::string&      ld_cmd)
1561    {
1562     rld::process::arg_container args;
1563
1564      if (rld::verbose ())
1565        std::cout << "linking: " << o.name () << std::endl;
1566
1567      std::string wrap = " -Wl,--wrap=";
1568
1569      rld::cc::make_ld_command (args);
1570
1571      rld::process::args_append (args,
1572                                 wrap + rld::join (tracer_.get_traces (), wrap));
1573      args.push_back (o.name ());
1574      rld::process::args_append (args, ld_cmd);
1575
1576      rld::process::tempfile out;
1577      rld::process::tempfile err;
1578      rld::process::status   status;
1579
1580      status = rld::process::execute (rld::cc::get_ld (),
1581                                      args,
1582                                      out.name (),
1583                                      err.name ());
1584
1585      if ((status.type != rld::process::status::normal) ||
1586          (status.code != 0))
1587      {
1588        err.output (rld::cc::get_ld (), std::cout);
1589        throw rld::error ("Linker error", "linking");
1590      }
1591      err.output (rld::cc::get_ld (), std::cout);
1592    }
1593
1594    void
1595    linker::dump (std::ostream& out) const
1596    {
1597      const rld::config::paths& cpaths = config.get_paths ();
1598      out << " Configuration Files: " << cpaths.size () << std::endl;
1599      for (rld::config::paths::const_iterator pi = cpaths.begin ();
1600           pi != cpaths.end ();
1601           ++pi)
1602      {
1603        out << "  " << (*pi) << std::endl;
1604      }
1605
1606      tracer_.dump (out);
1607    }
1608  }
1609}
1610
1611/**
1612 * RTEMS Trace Linker options. This needs to be rewritten to be like cc where
1613 * only a single '-' and long options is present. Anything after '--' is passed
1614 * to RTEMS's real linker.
1615 */
1616static struct option rld_opts[] = {
1617  { "help",        no_argument,            NULL,           'h' },
1618  { "version",     no_argument,            NULL,           'V' },
1619  { "verbose",     no_argument,            NULL,           'v' },
1620  { "warn",        no_argument,            NULL,           'w' },
1621  { "keep",        no_argument,            NULL,           'k' },
1622  { "compiler",    required_argument,      NULL,           'c' },
1623  { "linker",      required_argument,      NULL,           'l' },
1624  { "exec-prefix", required_argument,      NULL,           'E' },
1625  { "cflags",      required_argument,      NULL,           'f' },
1626  { "rtems",       required_argument,      NULL,           'r' },
1627  { "rtems-bsp",   required_argument,      NULL,           'B' },
1628  { "config",      required_argument,      NULL,           'C' },
1629  { "path",        required_argument,      NULL,           'P' },
1630  { "wrapper",     required_argument,      NULL,           'W' },
1631  { NULL,          0,                      NULL,            0 }
1632};
1633
1634void
1635usage (int exit_code)
1636{
1637  std::cout << "rtems-trace-ld [options] objects" << std::endl
1638            << "Options and arguments:" << std::endl
1639            << " -h          : help (also --help)" << std::endl
1640            << " -V          : print linker version number and exit (also --version)" << std::endl
1641            << " -v          : verbose (trace import parts), can supply multiple times" << std::endl
1642            << "               to increase verbosity (also --verbose)" << std::endl
1643            << " -w          : generate warnings (also --warn)" << std::endl
1644            << " -k          : keep temporary files (also --keep)" << std::endl
1645            << " -c compiler : target compiler is not standard (also --compiler)" << std::endl
1646            << " -l linker   : target linker is not standard (also --linker)" << std::endl
1647            << " -E prefix   : the RTEMS tool prefix (also --exec-prefix)" << std::endl
1648            << " -f cflags   : C compiler flags (also --cflags)" << std::endl
1649            << " -r path     : RTEMS path (also --rtems)" << std::endl
1650            << " -B bsp      : RTEMS arch/bsp (also --rtems-bsp)" << std::endl
1651            << " -W wrapper  : wrapper file name without ext (also --wrapper)" << std::endl
1652            << " -C ini      : user configuration INI file (also --config)" << std::endl
1653            << " -P path     : user configuration file search path (also --path)" << std::endl;
1654  ::exit (exit_code);
1655}
1656
1657static void
1658fatal_signal (int signum)
1659{
1660  signal (signum, SIG_DFL);
1661
1662  rld::process::temporaries_clean_up ();
1663
1664  /*
1665   * Get the same signal again, this time not handled, so its normal effect
1666   * occurs.
1667   */
1668  kill (getpid (), signum);
1669}
1670
1671static void
1672setup_signals (void)
1673{
1674  if (signal (SIGINT, SIG_IGN) != SIG_IGN)
1675    signal (SIGINT, fatal_signal);
1676#ifdef SIGHUP
1677  if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
1678    signal (SIGHUP, fatal_signal);
1679#endif
1680  if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
1681    signal (SIGTERM, fatal_signal);
1682#ifdef SIGPIPE
1683  if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
1684    signal (SIGPIPE, fatal_signal);
1685#endif
1686#ifdef SIGCHLD
1687  signal (SIGCHLD, SIG_DFL);
1688#endif
1689}
1690
1691int
1692main (int argc, char* argv[])
1693{
1694  int ec = 0;
1695
1696  setup_signals ();
1697
1698  try
1699  {
1700    rld::trace::linker linker;
1701    std::string        cc;
1702    std::string        ld;
1703    std::string        ld_cmd;
1704    std::string        configuration;
1705    std::string        path;
1706    std::string        trace = "tracer";
1707    std::string        wrapper;
1708    std::string        rtems_path;
1709    std::string        rtems_arch_bsp;
1710
1711    rld::set_cmdline (argc, argv);
1712
1713    while (true)
1714    {
1715      int opt = ::getopt_long (argc, argv, "hvwkVc:l:E:f:C:P:r:B:W:", rld_opts, NULL);
1716      if (opt < 0)
1717        break;
1718
1719      switch (opt)
1720      {
1721        case 'V':
1722          std::cout << "rtems-trace-ld (RTEMS Trace Linker) " << rld::version ()
1723                    << std::endl;
1724          ::exit (0);
1725          break;
1726
1727        case 'v':
1728          rld::verbose_inc ();
1729          break;
1730
1731        case 'w':
1732#if HAVE_WARNINGS
1733          warnings = true;
1734#endif
1735          break;
1736
1737        case 'k':
1738          rld::process::set_keep_temporary_files ();
1739          break;
1740
1741        case 'c':
1742          cc = optarg;
1743          break;
1744
1745        case 'l':
1746          ld = optarg;
1747          break;
1748
1749        case 'E':
1750          rld::cc::set_exec_prefix (optarg);
1751          break;
1752
1753        case 'f':
1754          rld::cc::append_flags (optarg, rld::cc::ft_cflags);
1755          break;
1756
1757        case 'r':
1758          rtems_path = optarg;
1759          break;
1760
1761        case 'B':
1762          rtems_arch_bsp = optarg;
1763          break;
1764
1765        case 'C':
1766          configuration = optarg;
1767          break;
1768
1769        case 'P':
1770          if (!path.empty ())
1771            path += ":";
1772          path += optarg;
1773          break;
1774
1775        case 'W':
1776          wrapper = optarg;
1777          break;
1778
1779        case '?':
1780          usage (3);
1781          break;
1782
1783        case 'h':
1784          usage (0);
1785          break;
1786      }
1787    }
1788
1789    /*
1790     * Set the program name.
1791     */
1792    rld::set_progname (argv[0]);
1793
1794    argc -= optind;
1795    argv += optind;
1796
1797    if (rld::verbose ())
1798    {
1799      std::cout << "RTEMS Trace Linker " << rld::version () << std::endl;
1800      std::cout << " " << rld::get_cmdline () << std::endl;
1801    }
1802
1803    /*
1804     * Load the arch/bsp value if provided.
1805     */
1806    if (!rtems_arch_bsp.empty ())
1807    {
1808      const std::string& prefix = rld::get_prefix ();
1809      if (rtems_path.empty () && prefix.empty ())
1810        throw rld::error ("No RTEMS path provided with arch/bsp", "options");
1811      if (!rtems_path.empty ())
1812        rld::rtems::set_path (rtems_path);
1813      else
1814        rld::rtems::set_path (prefix);
1815      rld::rtems::set_arch_bsp (rtems_arch_bsp);
1816    }
1817
1818    /**
1819     * Set the compiler and/or linker if provided.
1820     */
1821    if (!cc.empty ())
1822      rld::cc::set_cc (cc);
1823    if (!ld.empty ())
1824      rld::cc::set_ld (ld);
1825
1826    /*
1827     * Load the remaining command line arguments into the linker command line.
1828     */
1829    while (argc--)
1830    {
1831      /*
1832       * Create this value because 'ld_cmd += ' ' + *argv++' fails on clang.
1833       */
1834      std::string av = *argv++;
1835      ld_cmd += ' ' + av;
1836    }
1837    ld_cmd = rld::trim (ld_cmd);
1838
1839    /*
1840     * If there are no object files there is nothing to link.
1841     */
1842    if (ld_cmd.empty ())
1843      throw rld::error ("no trace linker options", "options");
1844
1845    /*
1846     * Perform a trace link.
1847     */
1848    try
1849    {
1850      linker.load_config (configuration, trace, path);
1851
1852      rld::process::tempfile c (".c");
1853      rld::process::tempfile o (".o");
1854
1855      if (!wrapper.empty ())
1856      {
1857        c.override (wrapper);
1858        c.keep ();
1859        o.override (wrapper);
1860        o.keep ();
1861      }
1862
1863      linker.generate_wrapper (c);
1864      linker.compile_wrapper (c, o);
1865      linker.link (o, ld_cmd);
1866
1867      if (rld::verbose ())
1868        linker.dump (std::cout);
1869    }
1870    catch (...)
1871    {
1872      throw;
1873    }
1874
1875  }
1876  catch (rld::error re)
1877  {
1878    std::cerr << "error: "
1879              << re.where << ": " << re.what
1880              << std::endl;
1881    ec = 10;
1882  }
1883  catch (std::exception e)
1884  {
1885    int   status;
1886    char* realname;
1887    realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
1888    std::cerr << "error: exception: " << realname << " [";
1889    ::free (realname);
1890    const std::type_info &ti = typeid (e);
1891    realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
1892    std::cerr << realname << "] " << e.what () << std::endl;
1893    ::free (realname);
1894    ec = 11;
1895  }
1896  catch (...)
1897  {
1898    /*
1899     * Helps to know if this happens.
1900     */
1901    std::cout << "error: unhandled exception" << std::endl;
1902    ec = 12;
1903  }
1904
1905  return ec;
1906}
Note: See TracBrowser for help on using the repository browser.