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

4.104.11
Last change on this file since 1703041 was 1703041, checked in by Chris Johns <chrisj@…>, on Mar 24, 2015 at 3:37:35 AM

rtems-tld: Add lock and buffer allocator support to generators.

Generators can control a lock and buffer allocation so a single
alloc can happen and a lock released.

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