source: rtems-tools/linkers/rtems-tld.cpp @ 40fd7a0

4.104.115
Last change on this file since 40fd7a0 was 40fd7a0, checked in by Chris Johns <chrisj@…>, on 09/01/14 at 03:26:47

rld: Split the file into a path module for path specific functions.

This allows resued for other parts of the system not dependent on
objcet files or archives.

  • Property mode set to 100644
File size: 25.0 KB
Line 
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  /**
56   * RTEMS Trace Linker.
57   */
58  namespace trace
59  {
60    /**
61     * A container of arguments.
62     */
63    typedef std::vector < std::string > function_args;
64
65    /**
66     * The return value.
67     */
68    typedef std::string function_return;
69
70    /**
71     * A function's signature.
72     */
73    struct signature
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. */
78
79      /**
80       * The default constructor.
81       */
82      signature ();
83
84      /**
85       * Construct the signature loading it from the configuration.
86       */
87      signature (const rld::config::record& record);
88
89      /**
90       * Return the function's declaration.
91       */
92      const std::string decl () const;
93    };
94
95    /**
96     * A container of signatures.
97     */
98    typedef std::map < std::string, signature > signatures;
99
100    /**
101     * A function is list of function signatures headers and defines that allow
102     * a function to be wrapped.
103     */
104    struct function
105    {
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. */
110
111      /**
112       * Load the function.
113       */
114      function (rld::config::config& config,
115                const std::string&   name);
116
117      /**
118       * Dump the function.
119       */
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. */
141
142      /**
143       * Default constructor.
144       */
145      generator ();
146
147      /**
148       * Load the generator.
149       */
150      generator (rld::config::config& config,
151                 const std::string&   name);
152
153      /**
154       * Dump the generator.
155       */
156      void dump (std::ostream& out) const;
157    };
158
159    /**
160     * Tracer.
161     */
162    class tracer
163    {
164    public:
165      tracer ();
166
167      /**
168       * Load the user's configuration.
169       */
170      void load (rld::config::config& config,
171                 const std::string&   section);
172
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
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
195      /**
196       * Dump the wrapper.
197       */
198      void dump (std::ostream& out) const;
199
200    private:
201
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. */
207    };
208
209    /**
210     * Trace Linker.
211     */
212    class linker
213    {
214    public:
215      linker ();
216
217      /**
218       * Load the user's configuration.
219       */
220      void load_config (const std::string& path,
221                        const std::string& trace);
222
223      /**
224       * Generate the C file.
225       */
226      void generate_wrapper ();
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. */
236      tracer              tracer_;  /**< The tracer */
237    };
238
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 ()
277    {
278    }
279
280    signature::signature (const rld::config::record& record)
281    {
282      /*
283       * There can only be one function signature in the configuration.
284       */
285      if (!record.single ())
286        throw rld::error ("duplicate", "signature: " + record.name);
287
288      name = record.name;
289
290      /*
291       * Signatures are defined as the return value then the arguments
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)
299        throw rld::error ("no return value", "signature: " + record.name);
300      if (si.size () == 1)
301          throw rld::error ("no arguments", "signature: " + record.name);
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
309    signature::decl () const
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    }
324
325    function::function (rld::config::config& config,
326                        const std::string&   name)
327      : name (name)
328    {
329      /*
330       * A function section optionally contain one or more records of:
331       *
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.
338       *
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.
341       */
342      const rld::config::section& section = config.get_section (name);
343
344      config.includes (section);
345
346      parse (config, section, "headers", "header", headers);
347      parse (config, section, "defines", "define", defines);
348
349      rld::strings sig_list;
350      section.get_record_items ("signatures", sig_list);
351
352      for (rld::strings::const_iterator sli = sig_list.begin ();
353           sli != sig_list.end ();
354           ++sli)
355      {
356        const rld::config::section& sig_sec = config.get_section (*sli);
357        for (rld::config::records::const_iterator si = sig_sec.recs.begin ();
358             si != sig_sec.recs.end ();
359             ++si)
360        {
361          signature sig (*si);
362          signatures_[sig.name] = sig;
363        }
364      }
365    }
366
367    void
368    function::dump (std::ostream& out) const
369    {
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)
375      {
376        out << "     " << (*hi) << std::endl;
377      }
378      out << "   Defines: " << defines.size () << std::endl;
379      for (rld::strings::const_iterator di = defines.begin ();
380           di != defines.end ();
381           ++di)
382      {
383        out << "     " << (*di) << std::endl;
384      }
385      out << "   Signatures: " << signatures_.size () << std::endl;
386      for (signatures::const_iterator si = signatures_.begin ();
387           si != signatures_.end ();
388           ++si)
389      {
390        const signature& sig = (*si).second;
391        out << "     " << sig.name << ": " << sig.decl () << ';' << std::endl;
392      }
393    }
394
395    generator::generator ()
396    {
397    }
398
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);
417
418      config.includes (section);
419
420      parse (config, section, "headers",     "header", headers);
421      parse (config, section, "defines",     "define", defines);
422      parse (config, section, "code-blocks", "code",   code, false);
423
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"));
427    }
428
429    void
430    generator::dump (std::ostream& out) const
431    {
432      out << "  Generator: " << name << std::endl
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      }
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
450          << "   Code blocks: " << std::endl;
451      for (rld::strings::const_iterator ci = code.begin ();
452           ci != code.end ();
453           ++ci)
454      {
455        out << "      > "
456            << rld::find_replace (*ci, "\n", "\n      | ") << std::endl;
457      }
458    }
459
460    tracer::tracer ()
461    {
462    }
463
464    void
465    tracer::load (rld::config::config& config,
466                  const std::string&   tname)
467    {
468      /*
469       * The configuration must contain a "section" section. This is the top level
470       * configuration and may contain:
471       *
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.
478       *
479       * The following records are required:
480       *
481       *  # name
482       *  # bsp
483       *  # trace
484       *  # functions
485       */
486      const rld::config::section& section = config.get_section (tname);
487
488      config.includes (section);
489
490      name = section.get_record_item ("name");
491      bsp  = section.get_record_item ("bsp");
492
493      load_functions (config, section);
494      load_traces (config, section);
495    }
496
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)
506      {
507        functions_.push_back (function (config, *fli));
508      }
509    }
510
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
531      {
532        gen = gens[0];
533      }
534
535      generator_ = generator (config, gen);
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 ("/*");
557        c.write_line (" * Generator: " + generator_.name);
558        c.write_line (" */");
559        c.write_lines (generator_.defines);
560        c.write_lines (generator_.headers);
561        c.write_line ("");
562        c.write_lines (generator_.code);
563
564        generate_traces (c);
565      }
566      catch (...)
567      {
568        c.close ();
569        throw;
570      }
571
572      c.close ();
573    }
574
575    void
576    tracer::generate_traces (rld::process::tempfile& c)
577    {
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
609      for (rld::strings::const_iterator ti = traces.begin ();
610           ti != traces.end ();
611           ++ti)
612      {
613        const std::string& trace = *ti;
614        bool               found = false;
615
616        for (functions::const_iterator fi = functions_.begin ();
617             fi != functions_.end ();
618             ++fi)
619        {
620          const function&            funcs = *fi;
621          signatures::const_iterator si = funcs.signatures_.find (trace);
622
623          if (si != funcs.signatures_.end ())
624          {
625            found = true;
626
627            const signature& sig = (*si).second;
628
629            c.write_line("");
630            c.write_line(sig.decl ());
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             */
639            if (sig.ret != "void")
640            {
641              c.write_line(" " + sig.ret + " ret;");
642              l = " ret =";
643            }
644
645            l += " " + generator_.map_sym_prefix + sig.name + '(';
646            for (size_t a = 0; a < sig.args.size (); ++a)
647            {
648              if (a)
649                l += ", ";
650              l += "a" + rld::to_string ((int) (a + 1));
651            }
652            l += ");";
653            c.write_line(l);
654
655            if (sig.ret != "void")
656            {
657              c.write_line(" return ret;");
658            }
659
660            c.write_line("}");
661          }
662        }
663
664        if (!found)
665          throw rld::error ("not found", "trace function: " + trace);
666      }
667    }
668
669    void
670    tracer::dump (std::ostream& out) const
671    {
672      out << " Tracer: " << name << std::endl
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)
678      {
679        out << "   " << (*ti) << std::endl;
680      }
681      out << "  Functions: " << functions_.size () << std::endl;
682      for (functions::const_iterator fi = functions_.begin ();
683           fi != functions_.end ();
684           ++fi)
685      {
686        (*fi).dump (out);
687      }
688      out << "  Generator: " << std::endl;
689      generator_.dump (out);
690    }
691
692    linker::linker ()
693    {
694    }
695
696    void
697    linker::load_config (const std::string& path,
698                         const std::string& trace)
699    {
700      config.clear ();
701      config.load (path);
702      tracer_.load (config, trace);
703    }
704
705    void
706    linker::generate_wrapper ()
707    {
708      tracer_.generate ();
709    }
710
711    void
712    linker::dump (std::ostream& out) const
713    {
714      const rld::config::paths& cpaths = config.get_paths ();
715      out << " Configuration Files: " << cpaths.size () << std::endl;
716      for (rld::config::paths::const_iterator pi = cpaths.begin ();
717           pi != cpaths.end ();
718           ++pi)
719      {
720        out << "  " << (*pi) << std::endl;
721      }
722
723      tracer_.dump (out);
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' },
738  { "keep",        no_argument,            NULL,           'k' },
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
756            << " -k        : keep temporary files (also --keep)" << std::endl
757            << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl
758            << " -c cflags : C compiler flags (also --cflags)" << std::endl
759            << " -C ini    : user configuration INI file (also --config)" << std::endl;
760  ::exit (exit_code);
761}
762
763static void
764fatal_signal (int signum)
765{
766  signal (signum, SIG_DFL);
767
768  rld::process::temporaries_clean_up ();
769
770  /*
771   * Get the same signal again, this time not handled, so its normal effect
772   * occurs.
773   */
774  kill (getpid (), signum);
775}
776
777static void
778setup_signals (void)
779{
780  if (signal (SIGINT, SIG_IGN) != SIG_IGN)
781    signal (SIGINT, fatal_signal);
782#ifdef SIGHUP
783  if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
784    signal (SIGHUP, fatal_signal);
785#endif
786  if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
787    signal (SIGTERM, fatal_signal);
788#ifdef SIGPIPE
789  if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
790    signal (SIGPIPE, fatal_signal);
791#endif
792#ifdef SIGCHLD
793  signal (SIGCHLD, SIG_DFL);
794#endif
795}
796
797int
798main (int argc, char* argv[])
799{
800  int ec = 0;
801
802  setup_signals ();
803
804  try
805  {
806    rld::trace::linker linker;
807    std::string        ld_cmd;
808    std::string        configuration;
809    std::string        trace = "tracer";
810    bool               exec_prefix_set = false;
811#if HAVE_WARNINGS
812    bool               warnings = false;
813#endif
814
815    while (true)
816    {
817      int opt = ::getopt_long (argc, argv, "hvwkVE:c:C:", rld_opts, NULL);
818      if (opt < 0)
819        break;
820
821      switch (opt)
822      {
823        case 'V':
824          std::cout << "rtems-trace-ld (RTEMS Trace Linker) " << rld::version ()
825                    << std::endl;
826          ::exit (0);
827          break;
828
829        case 'v':
830          rld::verbose_inc ();
831          break;
832
833        case 'w':
834#if HAVE_WARNINGS
835          warnings = true;
836#endif
837          break;
838
839        case 'k':
840          rld::process::set_keep_temporary_files ();
841          break;
842
843        case 'E':
844          exec_prefix_set = true;
845          rld::cc::exec_prefix = optarg;
846          break;
847
848        case 'c':
849          rld::cc::cflags = optarg;
850          break;
851
852        case 'C':
853          configuration = optarg;
854          break;
855
856        case '?':
857          usage (3);
858          break;
859
860        case 'h':
861          usage (0);
862          break;
863      }
864    }
865
866    argc -= optind;
867    argv += optind;
868
869    if (rld::verbose ())
870      std::cout << "RTEMS Trace Linker " << rld::version () << std::endl;
871
872    /*
873     * Load the remaining command line arguments into the linker command line.
874     */
875    while (argc--)
876    {
877      if (ld_cmd.length () != 0)
878        ld_cmd += " ";
879      ld_cmd += *argv++;
880    }
881
882    /*
883     * If there are no object files there is nothing to link.
884     */
885    if (ld_cmd.empty ())
886      throw rld::error ("no trace linker options", "options");
887
888    /*
889     * Perform a trace link.
890     */
891    try
892    {
893      linker.load_config (configuration, trace);
894      linker.generate_wrapper ();
895
896      if (rld::verbose ())
897        linker.dump (std::cout);
898    }
899    catch (...)
900    {
901      throw;
902    }
903
904  }
905  catch (rld::error re)
906  {
907    std::cerr << "error: "
908              << re.where << ": " << re.what
909              << std::endl;
910    ec = 10;
911  }
912  catch (std::exception e)
913  {
914    int   status;
915    char* realname;
916    realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
917    std::cerr << "error: exception: " << realname << " [";
918    ::free (realname);
919    const std::type_info &ti = typeid (e);
920    realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
921    std::cerr << realname << "] " << e.what () << std::endl;
922    ::free (realname);
923    ec = 11;
924  }
925  catch (...)
926  {
927    /*
928     * Helps to know if this happens.
929     */
930    std::cout << "error: unhandled exception" << std::endl;
931    ec = 12;
932  }
933
934  return ec;
935}
Note: See TracBrowser for help on using the repository browser.