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

Last change on this file was 0acb4d0, checked in by Ryan Long <ryan.long@…>, on 10/08/21 at 17:39:06

rtems-tld.cpp: Remove logically dead code

CID 1399595: Logically dead code in generate_traces().

Closes #4525

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