source: rtems-tools/linkers/rtems-syms.cpp @ aac2949

4.104.11
Last change on this file since aac2949 was aac2949, checked in by Chris Johns <chrisj@…>, on Oct 28, 2014 at 8:14:02 AM

linkers: Add kernel symbol support.

The rtems-sym tool has been changed from a basic map tool to now
provide an object file in the specific architecture containing
the symbols in the RTEMS kernel. It can still generate a map.

The object can be embedded or loaded. It cannot be both.

  • Property mode set to 100644
File size: 13.2 KB
Line 
1/*
2 * Copyright (c) 2011-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 Symbols Main manages opions, sequence of operations and exceptions.
22 *
23 */
24
25#if HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#include <fstream>
30#include <iomanip>
31#include <iostream>
32
33#include <cxxabi.h>
34#include <signal.h>
35#include <stdlib.h>
36#include <string.h>
37#include <unistd.h>
38
39#include <getopt.h>
40
41#include <rld.h>
42#include <rld-cc.h>
43#include <rld-outputter.h>
44#include <rld-process.h>
45#include <rld-symbols.h>
46
47#ifndef HAVE_KILL
48#define kill(p,s) raise(s)
49#endif
50
51/**
52 * Header text.
53 */
54static const char* c_header[] =
55{
56  "/*",
57  " * RTEMS Global Symbol Table",
58  " *  Automatically generated so no point in hacking on it.",
59  " */",
60  "",
61  "#if __bfin__ || __h8300__ || __v850__",
62  " extern unsigned char _rtems_rtl_base_globals[];",
63  " extern unsigned int _rtems_rtl_base_globals_size;",
64  "#else",
65  " extern unsigned char __rtems_rtl_base_globals[];",
66  " extern unsigned int __rtems_rtl_base_globals_size;",
67  "#endif",
68  "",
69  "asm(\"  .align   4\");",
70  "asm(\"__rtems_rtl_base_globals:\");",
71  0
72};
73
74static const char* c_trailer[] =
75{
76  "asm(\"  .byte    0\");",
77  "#if __mips__",
78  " asm(\"  .align 0\");",
79  "#else",
80  " asm(\"  .balign 1\");",
81  "#endif",
82  "asm(\"  .ascii \\\"\\xde\\xad\\xbe\\xef\\\"\");",
83  "asm(\"  .align   4\");",
84  "asm(\"__rtems_rtl_base_globals_size:\");",
85  "asm(\"  .long __rtems_rtl_base_globals_size - __rtems_rtl_base_globals\");",
86  "",
87  "void rtems_rtl_base_sym_global_add (const unsigned char* , unsigned int );",
88  0
89};
90
91static const char* c_rtl_call_body[] =
92{
93  "{",
94  "#if __bfin__ || __h8300__ || __v850__",
95  "  rtems_rtl_base_sym_global_add (_rtems_rtl_base_globals,",
96  "                                 _rtems_rtl_base_globals_size);",
97  "#else",
98  "  rtems_rtl_base_sym_global_add (__rtems_rtl_base_globals,",
99  "                                 __rtems_rtl_base_globals_size);",
100  "#endif",
101  "}",
102  0
103};
104
105/**
106 * Paint the data to the temporary file.
107 */
108static void
109temporary_file_paint (rld::process::tempfile& t, const char* lines[])
110{
111  for (int l = 0; lines[l]; ++l)
112    t.write_line (lines[l]);
113}
114
115/**
116 * The constructor trailer.
117 */
118static void
119c_constructor_trailer (rld::process::tempfile& c)
120{
121  temporary_file_paint (c, c_trailer);
122  c.write_line ("static void init(void) __attribute__ ((constructor));");
123  c.write_line ("static void init(void)");
124  temporary_file_paint (c, c_rtl_call_body);
125}
126
127/**
128 * The embedded trailer.
129 */
130static void
131c_embedded_trailer(rld::process::tempfile& c)
132{
133  temporary_file_paint (c, c_trailer);
134  c.write_line ("void rtems_rtl_base_global_syms_init(void);");
135  c.write_line ("void rtems_rtl_base_global_syms_init(void)");
136  temporary_file_paint (c, c_rtl_call_body);
137}
138
139/**
140 * Generate the symbol map object file for loading or linking into
141 * a running RTEMS machine.
142 */
143static void
144generate_asm (rld::process::tempfile& c,
145              rld::symbols::table&    symbols,
146              bool                    embed)
147{
148  temporary_file_paint (c, c_header);
149
150  for (rld::symbols::symtab::const_iterator si = symbols.externals ().begin ();
151       si != symbols.externals ().end ();
152       ++si)
153  {
154    const rld::symbols::symbol& sym = *((*si).second);
155
156    if (!sym.name ().empty ())
157    {
158      c.write_line ("asm(\"  .asciz \\\"" + sym.name () + "\\\"\");");
159
160      if (embed)
161      {
162        c.write_line ("#if __mips__");
163        c.write_line ("asm(\"  .align 0\");");
164        c.write_line ("#else");
165        c.write_line ("asm(\"  .balign 1\");");
166        c.write_line ("#endif");
167        c.write_line ("asm(\"  .long " + sym.name () + "\");");
168      }
169      else
170      {
171        std::stringstream oss;
172        oss << std::hex << std::setfill ('0') << std::setw (8) << sym.value ();
173        c.write_line ("asm(\"  .long 0x" + oss.str () + "\");");
174      }
175    }
176  }
177
178  if (embed)
179    c_embedded_trailer (c);
180  else
181    c_constructor_trailer (c);
182}
183
184static void
185generate_symmap (rld::process::tempfile& c,
186                 const std::string&      output,
187                 rld::symbols::table&    symbols,
188                 bool                    embed)
189{
190  c.open (true);
191
192  if (rld::verbose ())
193    std::cout << "symbol C file: " << c.name () << std::endl;
194
195  generate_asm (c, symbols, embed);
196
197  if (rld::verbose ())
198    std::cout << "symbol O file: " << output << std::endl;
199
200  rld::process::arg_container args;
201
202  rld::cc::make_cc_command (args);
203  rld::cc::append_flags (rld::cc::ft_cflags, args);
204
205  args.push_back ("-O2");
206  args.push_back ("-g");
207  args.push_back ("-c");
208  args.push_back ("-o");
209  args.push_back (output);
210  args.push_back (c.name ());
211
212  rld::process::tempfile out;
213  rld::process::tempfile err;
214  rld::process::status   status;
215
216  status = rld::process::execute (rld::cc::get_cc (),
217                                  args,
218                                  out.name (),
219                                  err.name ());
220
221  if ((status.type != rld::process::status::normal) ||
222      (status.code != 0))
223  {
224    err.output (rld::cc::get_cc (), std::cout);
225    throw rld::error ("Compiler error", "compiling wrapper");
226  }
227}
228
229/**
230 * RTEMS Linker options. This needs to be rewritten to be like cc where only a
231 * single '-' and long options is present.
232 */
233static struct option rld_opts[] = {
234  { "help",        no_argument,            NULL,           'h' },
235  { "version",     no_argument,            NULL,           'V' },
236  { "verbose",     no_argument,            NULL,           'v' },
237  { "warn",        no_argument,            NULL,           'w' },
238  { "keep",        no_argument,            NULL,           'k' },
239  { "embed",       no_argument,            NULL,           'e' },
240  { "symc",        required_argument,      NULL,           'S' },
241  { "output",      required_argument,      NULL,           'o' },
242  { "map",         required_argument,      NULL,           'm' },
243  { "cc",          required_argument,      NULL,           'C' },
244  { "exec-prefix", required_argument,      NULL,           'E' },
245  { "cflags",      required_argument,      NULL,           'c' },
246  { NULL,          0,                      NULL,            0 }
247};
248
249void
250usage (int exit_code)
251{
252  std::cout << "rtems-syms [options] kernel" << std::endl
253            << "Options and arguments:" << std::endl
254            << " -h        : help (also --help)" << std::endl
255            << " -V        : print linker version number and exit (also --version)" << std::endl
256            << " -v        : verbose (trace import parts), can supply multiple times" << std::endl
257            << "             to increase verbosity (also --verbose)" << std::endl
258            << " -w        : generate warnings (also --warn)" << std::endl
259            << " -k        : keep temporary files (also --keep)" << std::endl
260            << " -e        : embedded symbol table (also --embed)" << std::endl
261            << " -S        : symbol's C file (also --symc)" << std::endl
262            << " -o file   : output object file (also --output)" << std::endl
263            << " -m file   : output a map file (also --map)" << std::endl
264            << " -C file   : execute file as the target C compiler (also --cc)" << std::endl
265            << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl
266            << " -c cflags : C compiler flags (also --cflags)" << std::endl;
267  ::exit (exit_code);
268}
269
270static void
271fatal_signal (int signum)
272{
273  signal (signum, SIG_DFL);
274
275  rld::process::temporaries_clean_up ();
276
277  /*
278   * Get the same signal again, this time not handled, so its normal effect
279   * occurs.
280   */
281  kill (getpid (), signum);
282}
283
284static void
285setup_signals (void)
286{
287  if (signal (SIGINT, SIG_IGN) != SIG_IGN)
288    signal (SIGINT, fatal_signal);
289#ifdef SIGHUP
290  if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
291    signal (SIGHUP, fatal_signal);
292#endif
293  if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
294    signal (SIGTERM, fatal_signal);
295#ifdef SIGPIPE
296  if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
297    signal (SIGPIPE, fatal_signal);
298#endif
299#ifdef SIGCHLD
300  signal (SIGCHLD, SIG_DFL);
301#endif
302}
303
304int
305main (int argc, char* argv[])
306{
307  int ec = 0;
308
309  setup_signals ();
310
311  try
312  {
313    rld::files::cache   kernel;
314    rld::symbols::table symbols;
315    std::string         kernel_name;
316    std::string         output;
317    std::string         map;
318    std::string         cc;
319    std::string         symc;
320    bool                embed = false;
321    bool                warnings = false;
322
323    rld::set_cmdline (argc, argv);
324
325    while (true)
326    {
327      int opt = ::getopt_long (argc, argv, "hvVwS:o:m:E:c:C:", rld_opts, NULL);
328      if (opt < 0)
329        break;
330
331      switch (opt)
332      {
333        case 'V':
334          std::cout << "rtems-syms (RTEMS Symbols) " << rld::version ()
335                    << std::endl;
336          ::exit (0);
337          break;
338
339        case 'v':
340          rld::verbose_inc ();
341          break;
342
343        case 'w':
344          warnings = true;
345          break;
346
347        case 'k':
348          rld::process::set_keep_temporary_files ();
349          break;
350
351        case 'e':
352          embed = true;
353          break;
354
355        case 'o':
356          output = optarg;
357          break;
358
359        case 'm':
360          map = optarg;
361          break;
362
363        case 'C':
364          if (rld::cc::is_exec_prefix_set ())
365            std::cerr << "warning: exec-prefix ignored when CC provided" << std::endl;
366          rld::cc::set_cc (optarg);
367          break;
368
369        case 'E':
370          if (rld::cc::is_cc_set ())
371            std::cerr << "warning: exec-prefix ignored when CC provided" << std::endl;
372          rld::cc::set_exec_prefix (optarg);
373          break;
374
375        case 'c':
376          rld::cc::set_flags (optarg, rld::cc::ft_cflags);
377          break;
378
379        case 'S':
380          symc = optarg;
381          break;
382
383        case '?':
384          usage (3);
385          break;
386
387        case 'h':
388          usage (0);
389          break;
390      }
391    }
392
393    /*
394     * Set the program name.
395     */
396    rld::set_progname (argv[0]);
397
398    argc -= optind;
399    argv += optind;
400
401    if (rld::verbose ())
402      std::cout << "RTEMS Kernel Symbols " << rld::version () << std::endl;
403
404    /*
405     * If there are no object files there is nothing to link.
406     */
407    if (argc == 0)
408      throw rld::error ("no kernel file", "options");
409    if (argc != 1)
410      throw rld::error ("only one kernel file", "options");
411    if (output.empty ())
412      throw rld::error ("no output file", "options");
413
414    kernel_name = *argv;
415
416    if (rld::verbose ())
417      std::cout << "kernel: " << kernel_name << std::endl;
418
419    /*
420     * Load the symbols from the kernel.
421     */
422    try
423    {
424      kernel.open ();
425      kernel.add (kernel_name);
426      kernel.load_symbols (symbols, true);
427
428      /*
429       * If the full path to CC is not provided and the exec-prefix is not set
430       * by the command line see if it can be detected from the object file
431       * types. This must be after we have added the object files because they
432       * are used when detecting.
433       */
434      if (!cc.empty ())
435        rld::cc::set_cc (cc);
436      if (!rld::cc::is_cc_set () && !rld::cc::is_exec_prefix_set ())
437        rld::cc::set_exec_prefix (rld::elf::machine_type ());
438
439      rld::process::tempfile c (".c");
440
441      if (!symc.empty ())
442      {
443        c.override (symc);
444        c.keep ();
445      }
446
447      /*
448       * Generate and compile the symbol map.
449       */
450      generate_symmap (c, output, symbols, embed);
451
452      /*
453       * Create a map file is asked to.
454       */
455      if (!map.empty ())
456      {
457        std::ofstream mout;
458        mout.open (map);
459        if (!mout.is_open ())
460          throw rld::error ("map file open failed", "map");
461        mout << "RTEMS Kernel Symbols Map" << std::endl
462             << " kernel: " << kernel_name << std::endl
463             << std::endl;
464        rld::symbols::output (mout, symbols);
465        mout.close ();
466      }
467
468      kernel.close ();
469    }
470    catch (...)
471    {
472      kernel.close ();
473      throw;
474    }
475
476    kernel.close ();
477  }
478  catch (rld::error re)
479  {
480    std::cerr << "error: "
481              << re.where << ": " << re.what
482              << std::endl;
483    ec = 10;
484  }
485  catch (std::exception e)
486  {
487    int   status;
488    char* realname;
489    realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
490    std::cerr << "error: exception: " << realname << " [";
491    ::free (realname);
492    const std::type_info &ti = typeid (e);
493    realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
494    std::cerr << realname << "] " << e.what () << std::endl;
495    ::free (realname);
496    ec = 11;
497  }
498  catch (...)
499  {
500    /*
501     * Helps to know if this happens.
502     */
503    std::cout << "error: unhandled exception" << std::endl;
504    ec = 12;
505  }
506
507  return ec;
508}
Note: See TracBrowser for help on using the repository browser.