source: rtems-tools/rtemstoolkit/rld-process.cpp @ 0c0b2d4

4.10
Last change on this file since 0c0b2d4 was fdb1fe6, checked in by Chris Johns <chrisj@…>, on Oct 30, 2014 at 6:55:18 AM

linkers: Add base image symbol to ELF object file generation.

This change adds support to the rtems-syms code to generate a suitable
ELF object you can link to the base image kernel in the embed mode or
you can load with the run-time load mode.

The change fixes a bug in the framework where local ELF symbols
were being placed in the external symbol table. The external
symbol table has been removed and a global, weak and local set
of tables is now provided as this is more aligned with the ELF
format.

  • Property mode set to 100644
File size: 12.9 KB
Line 
1/*
2 * Copyright (c) 2011, 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#include "config.h"
18
19#include <ctype.h>
20#include <errno.h>
21#include <fcntl.h>
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <sys/stat.h>
26#include <unistd.h>
27
28#ifdef HAVE_SYS_WAIT_H
29#include <sys/wait.h>
30#endif
31
32#ifndef WIFEXITED
33#define WIFEXITED(S) (((S) & 0xff) == 0)
34#endif
35#ifndef WEXITSTATUS
36#define WEXITSTATUS(S) (((S) & 0xff00) >> 8)
37#endif
38#ifndef WIFSIGNALED
39#define WIFSIGNALED(S) (((S) & 0xff) != 0 && ((S) & 0xff) != 0x7f)
40#endif
41#ifndef WTERMSIG
42#define WTERMSIG(S) ((S) & 0x7f)
43#endif
44#ifndef WIFSTOPPED
45#define WIFSTOPPED WIFEXITED
46#endif
47#ifndef WSTOPSIG
48#define WSTOPSIG WEXITSTATUS
49#endif
50
51#if __WIN32__
52#define CREATE_MODE (S_IRUSR | S_IWUSR)
53#define OPEN_FLAGS  (O_BINARY)
54#else
55#define CREATE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)
56#define OPEN_FLAGS  (0)
57#endif
58
59#include <iostream>
60
61#include "rld.h"
62#include "rld-process.h"
63
64#include <libiberty.h>
65
66namespace rld
67{
68  namespace process
69  {
70    /**
71     * Global keep of temporary files if true. Used to help debug a system.
72     */
73    bool keep_temporary_files = false;
74
75    /**
76     * The temporary files.
77     */
78    temporary_files temporaries;
79
80    temporary_files::temporary_files ()
81    {
82    }
83
84    temporary_files::~temporary_files ()
85    {
86      clean_up ();
87    }
88
89    const std::string
90    temporary_files::get (const std::string& suffix, bool keep)
91    {
92      char* temp = ::make_temp_file (suffix.c_str ());
93
94      if (!temp)
95        throw rld::error ("bad temp name", "temp-file");
96
97      const std::string name = rld::find_replace (temp,
98                                                  RLD_PATH_SEPARATOR_STR RLD_PATH_SEPARATOR_STR,
99                                                  RLD_PATH_SEPARATOR_STR);
100      tempfile_ref ref (name, keep);
101      tempfiles.push_back (ref);
102      return name;
103    }
104
105    void
106    temporary_files::unlink (const tempfile_ref& ref)
107    {
108      if (!keep_temporary_files && !ref.keep)
109        rld::path::unlink (ref.name);
110    }
111
112    void
113    temporary_files::erase (const std::string& name)
114    {
115      for (tempfile_container::iterator tfi = tempfiles.begin ();
116           tfi != tempfiles.end ();
117           ++tfi)
118      {
119        if ((*tfi).name == name)
120        {
121          unlink (*tfi);
122          tempfiles.erase (tfi);
123          break;
124        }
125      }
126    }
127
128    void
129    temporary_files::keep (const std::string& name)
130    {
131      for (tempfile_container::iterator tfi = tempfiles.begin ();
132           tfi != tempfiles.end ();
133           ++tfi)
134      {
135        if ((*tfi).name == name)
136        {
137          (*tfi).keep = true;
138          break;
139        }
140      }
141    }
142
143    void
144    temporary_files::clean_up ()
145    {
146      for (tempfile_container::iterator tfi = tempfiles.begin ();
147           tfi != tempfiles.end ();
148           ++tfi)
149      {
150        unlink (*tfi);
151      }
152    }
153
154    tempfile::tempfile (const std::string& suffix, bool _keep)
155      : suffix (suffix),
156        overridden (false),
157        fd (-1),
158        level (0)
159    {
160      _name = temporaries.get (suffix, _keep);
161    }
162
163    tempfile::~tempfile ()
164    {
165      close ();
166      temporaries.erase (_name);
167    }
168
169    void
170    tempfile::open (bool writable)
171    {
172      if (fd < 0)
173      {
174        bool ok = rld::path::check_file (_name);
175        int  flags = writable ? O_RDWR : O_RDONLY;
176        int  mode = writable ? CREATE_MODE : 0;
177
178        if (writable && overridden)
179        {
180          flags |= O_CREAT | O_TRUNC | O_APPEND;
181        }
182        else
183        {
184          if (!ok)
185            throw rld::error ("Not found.", "tempfile open:" + _name);
186        }
187
188        level = 0;
189        fd = ::open (_name.c_str (), flags, mode);
190        if (fd < 0)
191          throw rld::error (::strerror (errno), "tempfile open:" + _name);
192      }
193    }
194
195    void
196    tempfile::close ()
197    {
198      if (fd != -1)
199      {
200        ::close (fd);
201        fd = -1;
202        level = 0;
203      }
204    }
205
206    void
207    tempfile::override (const std::string& name_)
208    {
209      if (fd >= 0)
210        throw rld::error ("Already open", "tempfile override");
211      rld::path::unlink (_name);
212      overridden = true;
213      _name = name_ + suffix;
214    }
215
216    void
217    tempfile::keep ()
218    {
219      temporaries.keep (_name);
220    }
221
222    const std::string&
223    tempfile::name () const
224    {
225      return _name;
226    }
227
228    size_t
229    tempfile::size ()
230    {
231      if (fd < 0)
232        return 0;
233
234      struct stat sb;
235      if (::stat (_name.c_str (), &sb) == 0)
236        return sb.st_size;
237
238      return 0;
239    }
240
241    void
242    tempfile::read (std::string& all)
243    {
244      all.clear ();
245      if (fd != -1)
246      {
247        if (level)
248          all.append (buf, level);
249        level = 0;
250        while (true)
251        {
252          int read = ::read (fd, buf, sizeof (buf) );
253          if (read < 0)
254            throw rld::error (::strerror (errno), "tempfile get read:" + _name);
255          else if (read == 0)
256            break;
257          else
258            all.append (buf, read);
259        }
260      }
261    }
262
263    void
264    tempfile::read_line (std::string& line)
265    {
266      line.clear ();
267      if (fd != -1)
268      {
269        bool reading = true;
270        while (reading)
271        {
272          if (level < (sizeof (buf) - 1))
273          {
274            ::memset (buf + level, 0, sizeof (buf) - level);
275            int read = ::read (fd, buf + level, sizeof (buf) - level - 1);
276            if (read < 0)
277              throw rld::error (::strerror (errno), "tempfile read:" + _name);
278            else if (read == 0)
279              reading = false;
280            else
281              level += read;
282          }
283          if (level)
284          {
285            char* lf = ::strchr (buf, '\n');
286            int   len = level;
287            if (lf)
288            {
289              len = lf - &buf[0] + 1;
290              reading = false;
291            }
292            line.append (buf, len);
293            level -= len;
294            if (level)
295              ::memmove (buf, &buf[len], level + 1);
296          }
297        }
298      }
299    }
300
301    void
302    tempfile::write (const std::string& s)
303    {
304      const char* p = s.c_str ();
305      size_t      l = s.length ();
306      while (l)
307      {
308        int written = ::write (fd, p, l);
309        if (written < 0)
310            throw rld::error (::strerror (errno), "tempfile write:" + _name);
311        if (written == 0)
312          break;
313        l -= written;
314      }
315    }
316
317    void
318    tempfile::write_line (const std::string& s)
319    {
320      write (s);
321      write (RLD_LINE_SEPARATOR);
322    }
323
324    void
325    tempfile::write_lines (const rld::strings& ss)
326    {
327      for (rld::strings::const_iterator ssi = ss.begin ();
328           ssi != ss.end ();
329           ++ssi)
330      {
331        write_line (*ssi);
332      }
333    }
334
335    void
336    tempfile::output (std::ostream& out)
337    {
338      std::string prefix;
339      output (prefix, out);
340    }
341
342    void
343    tempfile::output (const std::string& prefix,
344                      std::ostream&      out,
345                      bool               line_numbers)
346    {
347      if (fd == -1)
348      {
349        std::string line;
350        int         lc = 0;
351        open ();
352        while (true)
353        {
354          read_line (line);
355          ++lc;
356          if (line.empty () && (level == 0))
357            break;
358          if (!prefix.empty ())
359            out << prefix << ": ";
360          if (line_numbers)
361            out << lc << ": ";
362          out << line << std::flush;
363        }
364        close ();
365      }
366    }
367
368    void
369    set_keep_temporary_files ()
370    {
371      keep_temporary_files = true;
372    }
373
374    void
375    temporaries_clean_up ()
376    {
377      temporaries.clean_up ();
378    }
379
380    void
381    args_append (arg_container& args, const std::string& str)
382    {
383      rld::strings ss;
384      rld::split (ss, str);
385      for (rld::strings::iterator ssi = ss.begin ();
386           ssi != ss.end ();
387           ++ssi)
388      {
389        args.push_back (*ssi);
390      }
391    }
392
393    status
394    execute (const std::string& pname,
395             const std::string& command,
396             const std::string& outname,
397             const std::string& errname)
398    {
399      arg_container args;
400      parse_command_line (command, args);
401      return execute (pname, args, outname, errname);
402    }
403
404    status
405    execute (const std::string&   pname,
406             const arg_container& args,
407             const std::string&   outname,
408             const std::string&   errname)
409    {
410      if (rld::verbose (RLD_VERBOSE_TRACE))
411      {
412        std::cout << "execute: ";
413        for (size_t a = 0; a < args.size (); ++a)
414          std::cout << args[a] << ' ';
415        std::cout << std::endl;
416      }
417
418      const char** cargs = new const char* [args.size () + 1];
419
420      for (size_t a = 0; a < args.size (); ++a)
421        cargs[a] = args[a].c_str ();
422      cargs[args.size ()] = 0;
423
424      int err = 0;
425      int s = 0;
426
427      const char* serr = pex_one (PEX_LAST | PEX_SEARCH,
428                                  args[0].c_str (),
429                                  (char* const*) cargs,
430                                  pname.c_str (),
431                                  outname.c_str (),
432                                  errname.c_str (),
433                                  &s,
434                                  &err);
435
436      delete [] cargs;
437
438      if (serr)
439        throw rld::error ("execute: " + args[0], serr);
440      else if (err)
441        throw rld::error ("execute: " + args[0], ::strerror (err));
442
443      status _status;
444
445      if (rld::verbose (RLD_VERBOSE_TRACE))
446        std::cout << "execute: status: ";
447
448      if (WIFEXITED (s))
449      {
450        _status.type = status::normal;
451        _status.code = WEXITSTATUS (s);
452        if (rld::verbose (RLD_VERBOSE_TRACE))
453          std::cout << _status.code << std::endl;
454      }
455      else if (WIFSIGNALED (s))
456      {
457        _status.type = status::signal;
458        _status.code = WTERMSIG (s);
459        if (rld::verbose (RLD_VERBOSE_TRACE))
460          std::cout << "signal: " << _status.code << std::endl;
461      }
462      else if (WIFSTOPPED (s))
463      {
464        _status.type = status::stopped;
465        _status.code = WSTOPSIG (s);
466        if (rld::verbose (RLD_VERBOSE_TRACE))
467          std::cout << "stopped: " << _status.code << std::endl;
468      }
469      else
470        throw rld::error ("execute: " + args[0], "unknown status returned");
471
472      return _status;
473    }
474
475    /*
476     * The code is based on this C file:
477     *  http://cybertiggyr.com/pcm/src/parse.c
478     */
479    void
480    parse_command_line (const std::string& command, arg_container& args)
481    {
482      enum pstate
483      {
484        pstate_discard_space,
485        pstate_accumulate_quoted,
486        pstate_accumulate_raw
487      };
488
489      args.clear ();
490
491      const char quote = '"';
492      const char escape = '\\';
493      pstate     state = pstate_discard_space;
494      size_t     start = 0;
495      size_t     i = 0;
496
497      while (i < command.size ())
498      {
499        switch (state)
500        {
501          case pstate_discard_space:
502            if (command[i] == quote)
503            {
504              ++i;
505              start = i;
506              state = pstate_accumulate_quoted;
507            }
508            else if (::isspace (command[i]))
509            {
510              ++i;
511            }
512            else /* includes escape */
513            {
514              start = i;
515              state = pstate_accumulate_raw;
516            }
517            break;
518
519          case pstate_accumulate_quoted:
520            if (command[i] == quote)
521            {
522              args.push_back (command.substr (start, i - 1));
523              ++i;
524              state = pstate_discard_space;
525            }
526            else if ((command[i] == escape) && (command[i + 1] == quote))
527            {
528              i += 2;
529            }
530            else /* includes space */
531            {
532              ++i;
533            }
534            break;
535
536          case pstate_accumulate_raw:
537            if (command[i] == quote)
538            {
539              throw rld::error ("quote in token", "command parse");
540            }
541            else if ((command[i] == escape) && (command[i + 1] == quote))
542            {
543              i += 2;
544            }
545            else if (::isspace (command[i]))
546            {
547              args.push_back (command.substr (start, i - 1));
548              ++i;
549              state = pstate_discard_space;
550            }
551            else
552            {
553              ++i;
554            }
555            break;
556        }
557      }
558    }
559  }
560}
Note: See TracBrowser for help on using the repository browser.