source: rtems-tools/linkers/rtems-tld.cpp @ 097f1fd

4.104.115
Last change on this file since 097f1fd was 097f1fd, checked in by Chris Johns <chrisj@…>, on 08/07/14 at 08:15:06

rtms-tld: Refactor the code to match a better configuration format.

  • Property mode set to 100644
File size: 25.1 KB
RevLine 
[ea29902]1/*
2 * Copyright (c) 2014, 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 <locale>
34#include <sstream>
35
36#include <cxxabi.h>
37#include <signal.h>
38#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
41
42#include <getopt.h>
43
44#include <rld.h>
45#include <rld-cc.h>
46#include <rld-config.h>
47#include <rld-process.h>
48
49#ifndef HAVE_KILL
50#define kill(p,s) raise(s)
51#endif
52
53namespace rld
54{
55  /**
[b6d7f5f]56   * RTEMS Trace Linker.
[ea29902]57   */
[b6d7f5f]58  namespace trace
[ea29902]59  {
[b6d7f5f]60    /**
61     * A container of arguments.
62     */
63    typedef std::vector < std::string > function_args;
[ea29902]64
[b6d7f5f]65    /**
66     * The return value.
67     */
68    typedef std::string function_return;
[ea29902]69
[b6d7f5f]70    /**
71     * A function's signature.
72     */
[097f1fd]73    struct signature
[b6d7f5f]74    {
75      std::string     name; /**< The function's name. */
76      function_args   args; /**< The function's list of arguments. */
77      function_return ret;  /**< The fuctions return value. */
[ea29902]78
[b6d7f5f]79      /**
80       * The default constructor.
81       */
[097f1fd]82      signature ();
[ea29902]83
[b6d7f5f]84      /**
85       * Construct the signature loading it from the configuration.
86       */
[097f1fd]87      signature (const rld::config::record& record);
[ea29902]88
[b6d7f5f]89      /**
90       * Return the function's declaration.
91       */
92      const std::string decl () const;
93    };
[ea29902]94
[b6d7f5f]95    /**
[097f1fd]96     * A container of signatures.
[b6d7f5f]97     */
[097f1fd]98    typedef std::map < std::string, signature > signatures;
[ea29902]99
100    /**
[097f1fd]101     * A function is list of function signatures headers and defines that allow
102     * a function to be wrapped.
[ea29902]103     */
[097f1fd]104    struct function
[b6d7f5f]105    {
[097f1fd]106      std::string  name;        /**< The name of this wrapper. */
107      rld::strings headers;     /**< Include statements. */
108      rld::strings defines;     /**< Define statements. */
109      signatures   signatures_; /**< Signatures in this function. */
[b6d7f5f]110
111      /**
[097f1fd]112       * Load the function.
[b6d7f5f]113       */
[097f1fd]114      function (rld::config::config& config,
115                const std::string&   name);
[b6d7f5f]116
[058d502]117      /**
[097f1fd]118       * Dump the function.
[058d502]119       */
[097f1fd]120      void dump (std::ostream& out) const;
121    };
122
123    /**
124     * A container of functions.
125     */
126    typedef std::vector < function > functions;
127
128    /**
129     * A generator and that contains the functions used to trace arguments and
130     * return values. It also provides the implementation of those functions.
131     */
132    struct generator
133    {
134      std::string  name;            /**< The name of this wrapper. */
135      rld::strings headers;         /**< Include statements. */
136      rld::strings defines;         /**< Define statements. */
137      std::string  map_sym_prefix;  /**< Mapping symbol prefix. */
138      std::string  arg_trace;       /**< Code template to trace an argument. */
139      std::string  ret_trace;       /**< Code template to trace the return value. */
140      rld::strings code;            /**< Code block inserted before the trace code. */
[058d502]141
[0a21024]142      /**
[097f1fd]143       * Default constructor.
[0a21024]144       */
[097f1fd]145      generator ();
[0a21024]146
[b6d7f5f]147      /**
[097f1fd]148       * Load the generator.
149       */
150      generator (rld::config::config& config,
151                 const std::string&   name);
152
153      /**
154       * Dump the generator.
[b6d7f5f]155       */
156      void dump (std::ostream& out) const;
157    };
[ea29902]158
[b6d7f5f]159    /**
160     * Tracer.
161     */
162    class tracer
163    {
164    public:
165      tracer ();
[ea29902]166
[b6d7f5f]167      /**
168       * Load the user's configuration.
169       */
170      void load (rld::config::config& config,
171                 const std::string&   section);
[ea29902]172
[097f1fd]173      /**
174       * The the functions for the trace.
175       */
176      void load_functions (rld::config::config&        config,
177                           const rld::config::section& section);
178
179      /**
180       * The the traces for the tracer.
181       */
182      void load_traces (rld::config::config&        config,
183                        const rld::config::section& section);
184
[4fd758e]185      /**
186       * Generate the wrapper object file.
187       */
188      void generate ();
189
190      /**
191       * Generate the trace functions.
192       */
193      void generate_traces (rld::process::tempfile& c);
194
[b6d7f5f]195      /**
196       * Dump the wrapper.
197       */
198      void dump (std::ostream& out) const;
[ea29902]199
[b6d7f5f]200    private:
[ea29902]201
[097f1fd]202      std::string  name;       /**< The name of the trace. */
203      std::string  bsp;        /**< The BSP we are linking to. */
204      rld::strings traces;     /**< The functions to trace. */
205      functions    functions_; /**< The functions that can be traced. */
206      generator    generator_; /**< The tracer's generator. */
[b6d7f5f]207    };
208
209    /**
210     * Trace Linker.
[ea29902]211     */
[b6d7f5f]212    class linker
213    {
214    public:
215      linker ();
[ea29902]216
[b6d7f5f]217      /**
218       * Load the user's configuration.
219       */
220      void load_config (const std::string& path,
221                        const std::string& trace);
[ea29902]222
[b6d7f5f]223      /**
224       * Generate the C file.
225       */
[4fd758e]226      void generate_wrapper ();
[b6d7f5f]227
228      /**
229       * Dump the linker.
230       */
231      void dump (std::ostream& out) const;
232
233    private:
234
235      rld::config::config config;   /**< User configuration. */
[097f1fd]236      tracer              tracer_;  /**< The tracer */
[b6d7f5f]237    };
238
[097f1fd]239    /**
240     * Recursive parser for strings.
241     */
242    void
243    parse (rld::config::config&        config,
244           const rld::config::section& section,
245           const std::string&          sec_name,
246           const std::string&          rec_name,
247           rld::strings&               items,
248           bool                        split = true,
249           int                         depth = 0)
250    {
251      if (depth > 32)
252        throw rld::error ("too deep", "parsing: " + sec_name + '/' + rec_name);
253
254      rld::config::parse_items (section, rec_name, items, false, false, split);
255
256      rld::strings sl;
257
258      rld::config::parse_items (section, sec_name, sl);
259
260      for (rld::strings::iterator sli = sl.begin ();
261           sli != sl.end ();
262           ++sli)
263      {
264        const rld::config::section& sec = config.get_section (*sli);
265        parse (config, sec, sec_name, rec_name, items, split, depth + 1);
266      }
267
268      /*
269       * Make the items unique.
270       */
271      rld::strings::iterator ii;
272      ii = std::unique (items.begin (), items.end ());
273      items.resize (std::distance (items.begin (), ii));
274    }
275
276    signature::signature ()
[ea29902]277    {
[b6d7f5f]278    }
[ea29902]279
[097f1fd]280    signature::signature (const rld::config::record& record)
[b6d7f5f]281    {
282      /*
283       * There can only be one function signature in the configuration.
284       */
285      if (!record.single ())
[097f1fd]286        throw rld::error ("duplicate", "signature: " + record.name);
[b6d7f5f]287
288      name = record.name;
289
290      /*
[097f1fd]291       * Signatures are defined as the return value then the arguments
[b6d7f5f]292       * delimited by a comma and white space. No checking is made of the
293       * return value or arguments.
294       */
295      rld::strings si;
296      rld::config::parse_items (record, si);
297
298      if (si.size () == 0)
[097f1fd]299        throw rld::error ("no return value", "signature: " + record.name);
[b6d7f5f]300      if (si.size () == 1)
[097f1fd]301          throw rld::error ("no arguments", "signature: " + record.name);
[b6d7f5f]302
303      ret = si[0];
304      args.resize (si.size () - 1);
305      std::copy (si.begin ()  + 1, si.end (), args.begin ());
306    }
307
308    const std::string
[097f1fd]309    signature::decl () const
[b6d7f5f]310    {
311      std::string ds = ret + ' ' + name + '(';
312      int         arg = 0;
313      for (function_args::const_iterator ai = args.begin ();
314           ai != args.end ();
315           ++ai)
316        {
317          if (ai != args.begin ())
318            ds += ", ";
319          ds += (*ai) + " a" + rld::to_string (++arg);
320        }
321      ds += ')';
322      return ds;
323    }
[ea29902]324
[097f1fd]325    function::function (rld::config::config& config,
326                        const std::string&   name)
327      : name (name)
[b6d7f5f]328    {
[ea29902]329      /*
[097f1fd]330       * A function section optionally contain one or more records of:
[b6d7f5f]331       *
[097f1fd]332       * # headers     A list of sections containing headers or header records.
333       * # header      A list of include string that are single or double quoted.
334       * # defines     A list of sections containing defines or define record.
335       * # defines     A list of define string that are single or double quoted.
336       * # signatures  A list of section names of signatures.
337       * # includes    A list of files to include.
[ea29902]338       *
[b6d7f5f]339       * @note The quoting and list spliting is a little weak because a delimiter
340       *       in a quote should not be seen as a delimiter.
[ea29902]341       */
[b6d7f5f]342      const rld::config::section& section = config.get_section (name);
[ea29902]343
[097f1fd]344      config.includes (section);
345
[0a21024]346      parse (config, section, "headers", "header", headers);
347      parse (config, section, "defines", "define", defines);
348
[b6d7f5f]349      rld::strings sig_list;
[097f1fd]350      section.get_record_items ("signatures", sig_list);
[b6d7f5f]351
352      for (rld::strings::const_iterator sli = sig_list.begin ();
353           sli != sig_list.end ();
354           ++sli)
[ea29902]355      {
[b6d7f5f]356        const rld::config::section& sig_sec = config.get_section (*sli);
[097f1fd]357        for (rld::config::records::const_iterator si = sig_sec.recs.begin ();
358             si != sig_sec.recs.end ();
359             ++si)
[b6d7f5f]360        {
[097f1fd]361          signature sig (*si);
362          signatures_[sig.name] = sig;
[b6d7f5f]363        }
[ea29902]364      }
365    }
[b6d7f5f]366
[058d502]367    void
[097f1fd]368    function::dump (std::ostream& out) const
[058d502]369    {
[097f1fd]370      out << "   Function: " << name << std::endl
371          << "    Headers: " << headers.size () << std::endl;
372      for (rld::strings::const_iterator hi = headers.begin ();
373           hi != headers.end ();
374           ++hi)
[058d502]375      {
[097f1fd]376        out << "     " << (*hi) << std::endl;
[058d502]377      }
[097f1fd]378      out << "   Defines: " << defines.size () << std::endl;
379      for (rld::strings::const_iterator di = defines.begin ();
380           di != defines.end ();
381           ++di)
[058d502]382      {
[097f1fd]383        out << "     " << (*di) << std::endl;
[058d502]384      }
[097f1fd]385      out << "   Signatures: " << signatures_.size () << std::endl;
386      for (signatures::const_iterator si = signatures_.begin ();
387           si != signatures_.end ();
388           ++si)
[058d502]389      {
[097f1fd]390        const signature& sig = (*si).second;
391        out << "     " << sig.name << ": " << sig.decl () << ';' << std::endl;
[058d502]392      }
393    }
394
[097f1fd]395    generator::generator ()
[0a21024]396    {
[097f1fd]397    }
[0a21024]398
[097f1fd]399    generator::generator (rld::config::config& config,
400                          const std::string&   name)
401      : name (name)
402    {
403      /*
404       * A generator section optionally contain one or more records of:
405       *
406       * # headers     A list of sections containing headers or header records.
407       * # header      A list of include string that are single or double quoted.
408       * # defines     A list of sections containing defines or define record.
409       * # defines     A list of define string that are single or double quoted.
410       * # code-blocks A list of section names of code blocks.
411       * # includes    A list of files to include.
412       *
413       * @note The quoting and list spliting is a little weak because a delimiter
414       *       in a quote should not be seen as a delimiter.
415       */
416      const rld::config::section& section = config.get_section (name);
[0a21024]417
[097f1fd]418      config.includes (section);
[0a21024]419
[097f1fd]420      parse (config, section, "headers",     "header", headers);
421      parse (config, section, "defines",     "define", defines);
422      parse (config, section, "code-blocks", "code",   code, false);
[0a21024]423
[097f1fd]424      map_sym_prefix = section.get_record_item ("map-sym-prefix");
425      arg_trace = rld::dequote (section.get_record_item ("arg-trace"));
426      ret_trace = rld::dequote (section.get_record_item ("ret-trace"));
[0a21024]427    }
428
[b6d7f5f]429    void
[097f1fd]430    generator::dump (std::ostream& out) const
[b6d7f5f]431    {
[097f1fd]432      out << "  Generator: " << name << std::endl
[b6d7f5f]433          << "   Headers: " << headers.size () << std::endl;
434      for (rld::strings::const_iterator hi = headers.begin ();
435           hi != headers.end ();
436           ++hi)
437      {
438        out << "    " << (*hi) << std::endl;
439      }
440      out << "   Defines: " << defines.size () << std::endl;
441      for (rld::strings::const_iterator di = defines.begin ();
442           di != defines.end ();
443           ++di)
444      {
445        out << "    " << (*di) << std::endl;
446      }
[058d502]447      out << "   Mapping Symbol Prefix: " << map_sym_prefix << std::endl
448          << "   Arg Trace Code: " << arg_trace << std::endl
449          << "   Return Trace Code: " << ret_trace << std::endl
[097f1fd]450          << "   Code blocks: " << std::endl;
451      for (rld::strings::const_iterator ci = code.begin ();
452           ci != code.end ();
453           ++ci)
[b6d7f5f]454      {
[097f1fd]455        out << "      > "
456            << rld::find_replace (*ci, "\n", "\n      | ") << std::endl;
[b6d7f5f]457      }
458    }
459
460    tracer::tracer ()
461    {
462    }
463
464    void
465    tracer::load (rld::config::config& config,
[097f1fd]466                  const std::string&   tname)
[ea29902]467    {
468      /*
[097f1fd]469       * The configuration must contain a "section" section. This is the top level
470       * configuration and may contain:
[b6d7f5f]471       *
[097f1fd]472       *  # name      The name of trace being linked.
473       *  # bsp       The architecture/bsp name of the BSP.
474       *  # options   A list of options as per the long command line args.
475       *  # traces    The list of sections containing function lists to trace.
476       *  # functions The list of sections containing function details.
477       *  # include   The list of files to include.
[b6d7f5f]478       *
[097f1fd]479       * The following records are required:
[b6d7f5f]480       *
[097f1fd]481       *  # name
482       *  # bsp
483       *  # trace
484       *  # functions
[ea29902]485       */
[097f1fd]486      const rld::config::section& section = config.get_section (tname);
[ea29902]487
[097f1fd]488      config.includes (section);
[ea29902]489
[097f1fd]490      name = section.get_record_item ("name");
491      bsp  = section.get_record_item ("bsp");
[b6d7f5f]492
[097f1fd]493      load_functions (config, section);
494      load_traces (config, section);
495    }
[ea29902]496
[097f1fd]497    void
498    tracer::load_functions (rld::config::config&        config,
499                            const rld::config::section& section)
500    {
501      rld::strings fl;
502      rld::config::parse_items (section, "functions", fl, true);
503      for (rld::strings::const_iterator fli = fl.begin ();
504           fli != fl.end ();
505           ++fli)
[b6d7f5f]506      {
[097f1fd]507        functions_.push_back (function (config, *fli));
[b6d7f5f]508      }
[097f1fd]509    }
[ea29902]510
[097f1fd]511    void
512    tracer::load_traces (rld::config::config&        config,
513                         const rld::config::section& section)
514    {
515      parse (config, section, "traces", "trace", traces);
516
517      rld::strings gens;
518      std::string  gen;
519
520      parse (config, section, "traces", "generator", gens);
521
522      if (gens.size () > 1)
523        throw rld::error ("duplicate generators", "tracer: " + section.name);
524
525      if (gens.size () == 0)
526      {
527        gen =
528          config.get_section ("default-generator").get_record_item ("generator");
529      }
530      else
[ea29902]531      {
[097f1fd]532        gen = gens[0];
[4fd758e]533      }
534
[097f1fd]535      generator_ = generator (config, gen);
[4fd758e]536    }
537
538    void
539    tracer::generate ()
540    {
541      rld::process::tempfile c (".c");
542
543      c.open (true);
544
545      if (rld::verbose ())
546        std::cout << "wrapper C file: " << c.name () << std::endl;
547
548      try
549      {
550        c.write_line ("/*");
551        c.write_line (" * RTEMS Trace Linker Wrapper");
552        c.write_line (" *  Automatically generated.");
553        c.write_line (" */");
554
555        c.write_line ("");
556        c.write_line ("/*");
[097f1fd]557        c.write_line (" * Generator: " + generator_.name);
[4fd758e]558        c.write_line (" */");
[097f1fd]559        c.write_lines (generator_.defines);
560        c.write_lines (generator_.headers);
561        c.write_line ("");
562        c.write_lines (generator_.code);
[4fd758e]563
564        generate_traces (c);
565      }
566      catch (...)
567      {
568        c.close ();
569        throw;
[ea29902]570      }
571
[4fd758e]572      c.close ();
573    }
574
575    void
576    tracer::generate_traces (rld::process::tempfile& c)
577    {
[097f1fd]578      for (functions::const_iterator fi = functions_.begin ();
579           fi != functions_.end ();
580           ++fi)
581      {
582        const function& funcs = *fi;
583
584        for (rld::strings::const_iterator ti = traces.begin ();
585             ti != traces.end ();
586             ++ti)
587        {
588          const std::string&         trace = *ti;
589          signatures::const_iterator si = funcs.signatures_.find (trace);
590
591          if (si != funcs.signatures_.end ())
592          {
593            c.write_line ("");
594            c.write_line ("/*");
595            c.write_line (" * Function: " + funcs.name);
596            c.write_line (" */");
597            c.write_lines (funcs.defines);
598            c.write_lines (funcs.headers);
599            break;
600          }
601        }
602      }
603
604      c.write_line ("");
605      c.write_line ("/*");
606      c.write_line (" * Wrappers.");
607      c.write_line (" */");
608
[4fd758e]609      for (rld::strings::const_iterator ti = traces.begin ();
610           ti != traces.end ();
611           ++ti)
612      {
[097f1fd]613        const std::string& trace = *ti;
[4fd758e]614        bool               found = false;
615
[097f1fd]616        for (functions::const_iterator fi = functions_.begin ();
617             fi != functions_.end ();
618             ++fi)
[4fd758e]619        {
[097f1fd]620          const function&            funcs = *fi;
621          signatures::const_iterator si = funcs.signatures_.find (trace);
[4fd758e]622
[097f1fd]623          if (si != funcs.signatures_.end ())
[4fd758e]624          {
625            found = true;
626
[097f1fd]627            const signature& sig = (*si).second;
[4fd758e]628
629            c.write_line("");
[097f1fd]630            c.write_line(sig.decl ());
[4fd758e]631            c.write_line("{");
632
633            std::string l;
634
635            /*
636             * @todo Need to define as part of the function signature if ret
637             *       processing is required.
638             */
[097f1fd]639            if (sig.ret != "void")
[4fd758e]640            {
[097f1fd]641              c.write_line(" " + sig.ret + " ret;");
[4fd758e]642              l = " ret =";
643            }
644
[097f1fd]645            l += " " + generator_.map_sym_prefix + sig.name + '(';
646            for (size_t a = 0; a < sig.args.size (); ++a)
[4fd758e]647            {
648              if (a)
649                l += ", ";
650              l += "a" + rld::to_string ((int) (a + 1));
651            }
652            l += ");";
653            c.write_line(l);
654
[097f1fd]655            if (sig.ret != "void")
[4fd758e]656            {
657              c.write_line(" return ret;");
658            }
659
660            c.write_line("}");
661          }
662        }
663
664        if (!found)
[097f1fd]665          throw rld::error ("not found", "trace function: " + trace);
[4fd758e]666      }
[b6d7f5f]667    }
[ea29902]668
[b6d7f5f]669    void
670    tracer::dump (std::ostream& out) const
671    {
672      out << " Tracer: " << name << std::endl
[097f1fd]673          << "  BSP: " << bsp << std::endl
674          << "  Traces: " << traces.size () << std::endl;
675      for (rld::strings::const_iterator ti = traces.begin ();
676           ti != traces.end ();
677           ++ti)
[b6d7f5f]678      {
[097f1fd]679        out << "   " << (*ti) << std::endl;
[b6d7f5f]680      }
[097f1fd]681      out << "  Functions: " << functions_.size () << std::endl;
682      for (functions::const_iterator fi = functions_.begin ();
683           fi != functions_.end ();
684           ++fi)
[4fd758e]685      {
[097f1fd]686        (*fi).dump (out);
[4fd758e]687      }
[097f1fd]688      out << "  Generator: " << std::endl;
689      generator_.dump (out);
[b6d7f5f]690    }
[ea29902]691
[b6d7f5f]692    linker::linker ()
693    {
[ea29902]694    }
695
[b6d7f5f]696    void
697    linker::load_config (const std::string& path,
698                         const std::string& trace)
[ea29902]699    {
[b6d7f5f]700      config.clear ();
701      config.load (path);
[097f1fd]702      tracer_.load (config, trace);
[ea29902]703    }
704
[4fd758e]705    void
706    linker::generate_wrapper ()
707    {
[097f1fd]708      tracer_.generate ();
[4fd758e]709    }
710
[b6d7f5f]711    void
712    linker::dump (std::ostream& out) const
[ea29902]713    {
[b6d7f5f]714      const rld::config::paths& cpaths = config.get_paths ();
[4fd758e]715      out << " Configuration Files: " << cpaths.size () << std::endl;
[b6d7f5f]716      for (rld::config::paths::const_iterator pi = cpaths.begin ();
717           pi != cpaths.end ();
718           ++pi)
[ea29902]719      {
[b6d7f5f]720        out << "  " << (*pi) << std::endl;
[ea29902]721      }
[b6d7f5f]722
[097f1fd]723      tracer_.dump (out);
[ea29902]724    }
725  }
726}
727
728/**
729 * RTEMS Trace Linker options. This needs to be rewritten to be like cc where
730 * only a single '-' and long options is present. Anything after '--' is passed
731 * to RTEMS's real linker.
732 */
733static struct option rld_opts[] = {
734  { "help",        no_argument,            NULL,           'h' },
735  { "version",     no_argument,            NULL,           'V' },
736  { "verbose",     no_argument,            NULL,           'v' },
737  { "warn",        no_argument,            NULL,           'w' },
[4fd758e]738  { "keep",        no_argument,            NULL,           'k' },
[ea29902]739  { "exec-prefix", required_argument,      NULL,           'E' },
740  { "march",       required_argument,      NULL,           'a' },
741  { "mcpu",        required_argument,      NULL,           'c' },
742  { "config",      required_argument,      NULL,           'C' },
743  { NULL,          0,                      NULL,            0 }
744};
745
746void
747usage (int exit_code)
748{
749  std::cout << "rtems-trace-ld [options] objects" << std::endl
750            << "Options and arguments:" << std::endl
751            << " -h        : help (also --help)" << std::endl
752            << " -V        : print linker version number and exit (also --version)" << std::endl
753            << " -v        : verbose (trace import parts), can supply multiple times" << std::endl
754            << "             to increase verbosity (also --verbose)" << std::endl
755            << " -w        : generate warnings (also --warn)" << std::endl
[4fd758e]756            << " -k        : keep temporary files (also --keep)" << std::endl
[ea29902]757            << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl
758            << " -a march  : machine architecture (also --march)" << std::endl
759            << " -c cpu    : machine architecture's CPU (also --mcpu)" << std::endl
760            << " -C ini    : user configuration INI file (also --config)" << std::endl;
761  ::exit (exit_code);
762}
763
764static void
765fatal_signal (int signum)
766{
767  signal (signum, SIG_DFL);
768
[4fd758e]769  rld::process::temporaries_clean_up ();
[ea29902]770
771  /*
772   * Get the same signal again, this time not handled, so its normal effect
773   * occurs.
774   */
775  kill (getpid (), signum);
776}
777
778static void
779setup_signals (void)
780{
781  if (signal (SIGINT, SIG_IGN) != SIG_IGN)
782    signal (SIGINT, fatal_signal);
783#ifdef SIGHUP
784  if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
785    signal (SIGHUP, fatal_signal);
786#endif
787  if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
788    signal (SIGTERM, fatal_signal);
789#ifdef SIGPIPE
790  if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
791    signal (SIGPIPE, fatal_signal);
792#endif
793#ifdef SIGCHLD
794  signal (SIGCHLD, SIG_DFL);
795#endif
796}
797
798int
799main (int argc, char* argv[])
800{
801  int ec = 0;
802
803  setup_signals ();
804
805  try
806  {
[b6d7f5f]807    rld::trace::linker linker;
808    std::string        ld_cmd;
809    std::string        configuration;
810    std::string        trace = "tracer";
811    bool               exec_prefix_set = false;
[ea29902]812#if HAVE_WARNINGS
[b6d7f5f]813    bool               warnings = false;
[ea29902]814#endif
815
816    while (true)
817    {
[4fd758e]818      int opt = ::getopt_long (argc, argv, "hvwkVE:a:c:C:", rld_opts, NULL);
[ea29902]819      if (opt < 0)
820        break;
821
822      switch (opt)
823      {
824        case 'V':
825          std::cout << "rtems-trace-ld (RTEMS Trace Linker) " << rld::version ()
826                    << std::endl;
827          ::exit (0);
828          break;
829
830        case 'v':
831          rld::verbose_inc ();
832          break;
833
834        case 'w':
835#if HAVE_WARNINGS
836          warnings = true;
837#endif
838          break;
839
[4fd758e]840        case 'k':
841          rld::process::set_keep_temporary_files ();
842          break;
843
[ea29902]844        case 'E':
845          exec_prefix_set = true;
846          rld::cc::exec_prefix = optarg;
847          break;
848
849        case 'a':
850          rld::cc::march = optarg;
851          break;
852
853        case 'c':
854          rld::cc::mcpu = optarg;
855          break;
856
857        case 'C':
858          configuration = optarg;
859          break;
860
861        case '?':
862          usage (3);
863          break;
864
865        case 'h':
866          usage (0);
867          break;
868      }
869    }
870
871    argc -= optind;
872    argv += optind;
873
874    if (rld::verbose ())
875      std::cout << "RTEMS Trace Linker " << rld::version () << std::endl;
876
877    /*
878     * Load the remaining command line arguments into the linker command line.
879     */
880    while (argc--)
881    {
882      if (ld_cmd.length () != 0)
883        ld_cmd += " ";
884      ld_cmd += *argv++;
885    }
886
887    /*
888     * If there are no object files there is nothing to link.
889     */
890    if (ld_cmd.empty ())
891      throw rld::error ("no trace linker options", "options");
892
893    /*
894     * Perform a trace link.
895     */
896    try
897    {
[b6d7f5f]898      linker.load_config (configuration, trace);
[4fd758e]899      linker.generate_wrapper ();
900
901      if (rld::verbose ())
902        linker.dump (std::cout);
[ea29902]903    }
904    catch (...)
905    {
906      throw;
907    }
908
909  }
910  catch (rld::error re)
911  {
912    std::cerr << "error: "
913              << re.where << ": " << re.what
914              << std::endl;
915    ec = 10;
916  }
917  catch (std::exception e)
918  {
919    int   status;
920    char* realname;
921    realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
922    std::cerr << "error: exception: " << realname << " [";
923    ::free (realname);
924    const std::type_info &ti = typeid (e);
925    realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
926    std::cerr << realname << "] " << e.what () << std::endl;
927    ::free (realname);
928    ec = 11;
929  }
930  catch (...)
931  {
932    /*
933     * Helps to know if this happens.
934     */
935    std::cout << "error: unhandled exception" << std::endl;
936    ec = 12;
937  }
938
939  return ec;
940}
Note: See TracBrowser for help on using the repository browser.