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

4.104.115
Last change on this file since b69cd3f was b988768, checked in by Chris Johns <chrisj@…>, on 03/26/15 at 06:08:18

trace-linker: Add Trace Buffering support.

Trace buffering traces into a static buffer complete with timestamp
and the executing context.

A shell command provides access to the data.

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