mirror of
https://git.rtems.org/rtems-tools/
synced 2025-05-15 09:36:52 +08:00
1314 lines
33 KiB
C++
1314 lines
33 KiB
C++
/*
|
|
* Copyright (c) 2012, Chris Johns <chrisj@rtems.org>
|
|
*
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
/**
|
|
* @file
|
|
*
|
|
* @ingroup rtems_rld
|
|
*
|
|
* @brief RTEMS RAP Manager lets you look at and play with RAP files.
|
|
*
|
|
*/
|
|
|
|
#if HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <algorithm>
|
|
#include <iomanip>
|
|
#include <iostream>
|
|
#include <vector>
|
|
|
|
#include <cxxabi.h>
|
|
#include <signal.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include <getopt.h>
|
|
|
|
#include <rld.h>
|
|
#include <rld-compression.h>
|
|
#include <rld-files.h>
|
|
#include <rld-process.h>
|
|
#include <rld-rap.h>
|
|
#include <rld-rtems.h>
|
|
|
|
#include <rtems-utils.h>
|
|
|
|
#ifndef HAVE_KILL
|
|
#define kill(p,s) raise(s)
|
|
#endif
|
|
|
|
/**
|
|
* RTEMS Application.
|
|
*/
|
|
namespace rap
|
|
{
|
|
/**
|
|
* The names of the RAP sections.
|
|
*/
|
|
static const char* section_names[6] =
|
|
{
|
|
".text",
|
|
".const",
|
|
".ctor",
|
|
".dtor",
|
|
".data",
|
|
".bss"
|
|
};
|
|
|
|
/**
|
|
* A relocation record.
|
|
*/
|
|
struct relocation
|
|
{
|
|
uint32_t info;
|
|
uint32_t offset;
|
|
uint32_t addend;
|
|
std::string symname;
|
|
off_t rap_off;
|
|
|
|
relocation ();
|
|
|
|
void output ();
|
|
};
|
|
|
|
typedef std::vector < relocation > relocations;
|
|
|
|
/**
|
|
* Relocation offset sorter for the relocations container.
|
|
*/
|
|
class reloc_offset_compare
|
|
{
|
|
public:
|
|
bool operator () (const relocation& lhs,
|
|
const relocation& rhs) const {
|
|
return lhs.offset < rhs.offset;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* A RAP section.
|
|
*/
|
|
struct section
|
|
{
|
|
std::string name;
|
|
uint32_t size;
|
|
uint32_t alignment;
|
|
uint8_t* data;
|
|
uint32_t relocs_size;
|
|
relocations relocs;
|
|
bool rela;
|
|
off_t rap_off;
|
|
|
|
section ();
|
|
~section ();
|
|
|
|
void load_data (rld::compress::compressor& comp);
|
|
void load_relocs (rld::compress::compressor& comp);
|
|
};
|
|
|
|
/**
|
|
* Section detail
|
|
*/
|
|
struct section_detail
|
|
{
|
|
uint32_t name; //< The offset in the strtable.
|
|
uint32_t offset; //< The offset in the rap section.
|
|
uint32_t id; //< The rap id.
|
|
uint32_t size; //< The size of the elf section.
|
|
uint32_t obj; //< The obj id.
|
|
|
|
/* Constructor */
|
|
section_detail (const section_detail& s);
|
|
section_detail ();
|
|
};
|
|
|
|
section_detail::section_detail (const section_detail& s)
|
|
: name (s.name),
|
|
offset (s.offset),
|
|
id (s.id),
|
|
size (s.size),
|
|
obj (s.obj)
|
|
{
|
|
}
|
|
|
|
section_detail::section_detail ()
|
|
: name (0),
|
|
offset (0),
|
|
id (0),
|
|
size (0),
|
|
obj (0)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* A container of section_detail
|
|
*/
|
|
typedef std::list < section_detail > section_details;
|
|
|
|
/**
|
|
* A RAP file.
|
|
*/
|
|
struct file
|
|
{
|
|
enum {
|
|
rap_comp_buffer = 2 * 1024
|
|
};
|
|
|
|
std::string header;
|
|
size_t rhdr_len;
|
|
uint32_t rhdr_length;
|
|
uint32_t rhdr_version;
|
|
std::string rhdr_compression;
|
|
uint32_t rhdr_checksum;
|
|
|
|
off_t machine_rap_off;
|
|
uint32_t machinetype;
|
|
uint32_t datatype;
|
|
uint32_t class_;
|
|
|
|
off_t layout_rap_off;
|
|
std::string init;
|
|
uint32_t init_off;
|
|
std::string fini;
|
|
uint32_t fini_off;
|
|
|
|
off_t strtab_rap_off;
|
|
uint32_t strtab_size;
|
|
uint8_t* strtab;
|
|
|
|
off_t symtab_rap_off;
|
|
uint32_t symtab_size;
|
|
uint8_t* symtab;
|
|
|
|
off_t relocs_rap_off;
|
|
uint32_t relocs_size; /* not used */
|
|
|
|
off_t detail_rap_off;
|
|
uint32_t obj_num;
|
|
uint8_t** obj_name;
|
|
uint32_t* sec_num;
|
|
uint8_t* rpath;
|
|
uint32_t rpathlen;
|
|
uint8_t* str_detail;
|
|
section_details sec_details;
|
|
|
|
section secs[rld::rap::rap_secs];
|
|
|
|
/**
|
|
* Open a RAP file and read the header.
|
|
*/
|
|
file (const std::string& name, bool warnings);
|
|
|
|
/**
|
|
* Close the RAP file.
|
|
*/
|
|
~file ();
|
|
|
|
/**
|
|
* Parse header.
|
|
*/
|
|
void parse_header ();
|
|
|
|
/**
|
|
* Load the file.
|
|
*/
|
|
void load ();
|
|
|
|
/**
|
|
* Expand the image.
|
|
*/
|
|
void expand ();
|
|
|
|
/**
|
|
* Load details.
|
|
*/
|
|
void load_details(rld::compress::compressor& comp);
|
|
|
|
/**
|
|
* The name.
|
|
*/
|
|
const std::string name () const;
|
|
|
|
/**
|
|
* The number of symbols in the symbol table.
|
|
*/
|
|
int symbols () const;
|
|
|
|
/**
|
|
* Return a symbol given an index.
|
|
*/
|
|
void symbol (int index,
|
|
uint32_t& data,
|
|
uint32_t& name,
|
|
uint32_t& value) const;
|
|
|
|
/**
|
|
* Return the string from the string table.
|
|
*/
|
|
const char* string (int index);
|
|
|
|
private:
|
|
|
|
bool warnings;
|
|
rld::files::image image;
|
|
};
|
|
|
|
template < typename T > T
|
|
get_value (const uint8_t* data)
|
|
{
|
|
T v = 0;
|
|
for (size_t b = 0; b < sizeof (T); ++b)
|
|
{
|
|
v <<= 8;
|
|
v |= (T) data[b];
|
|
}
|
|
return v;
|
|
}
|
|
|
|
relocation::relocation ()
|
|
: info (0),
|
|
offset (0),
|
|
addend (0),
|
|
rap_off (0)
|
|
{
|
|
}
|
|
|
|
void
|
|
relocation::output ()
|
|
{
|
|
std::cout << std::hex << std::setfill ('0')
|
|
<< "0x" << std::setw (8) << info
|
|
<< " 0x" << std::setw (8) << offset
|
|
<< " 0x" << std::setw(8) << addend
|
|
<< std::dec << std::setfill (' ')
|
|
<< " " << symname;
|
|
}
|
|
|
|
section::section ()
|
|
: size (0),
|
|
alignment (0),
|
|
data (0),
|
|
relocs_size (0),
|
|
relocs (0),
|
|
rela (false),
|
|
rap_off (0)
|
|
{
|
|
}
|
|
|
|
section::~section ()
|
|
{
|
|
if (data)
|
|
delete [] data;
|
|
}
|
|
|
|
void
|
|
section::load_data (rld::compress::compressor& comp)
|
|
{
|
|
rap_off = comp.offset ();
|
|
if (size)
|
|
{
|
|
data = new uint8_t[size];
|
|
if (comp.read (data, size) != size)
|
|
throw rld::error ("Reading section data failed", "rapper");
|
|
}
|
|
}
|
|
|
|
void
|
|
section::load_relocs (rld::compress::compressor& comp)
|
|
{
|
|
uint32_t header;
|
|
comp >> header;
|
|
|
|
rela = header & RAP_RELOC_RELA ? true : false;
|
|
relocs_size = header & ~RAP_RELOC_RELA;
|
|
|
|
if (relocs_size)
|
|
{
|
|
for (uint32_t r = 0; r < relocs_size; ++r)
|
|
{
|
|
relocation reloc;
|
|
|
|
reloc.rap_off = comp.offset ();
|
|
|
|
comp >> reloc.info
|
|
>> reloc.offset;
|
|
|
|
if (((reloc.info & RAP_RELOC_STRING) == 0) || rela)
|
|
comp >> reloc.addend;
|
|
|
|
if ((reloc.info & RAP_RELOC_STRING) != 0)
|
|
{
|
|
if ((reloc.info & RAP_RELOC_STRING_EMBED) == 0)
|
|
{
|
|
size_t symname_size = (reloc.info & ~(3 << 30)) >> 8;
|
|
reloc.symname.resize (symname_size);
|
|
size_t symname_read = comp.read ((void*) reloc.symname.c_str (), symname_size);
|
|
if (symname_read != symname_size)
|
|
throw rld::error ("Reading reloc symbol name failed", "rapper");
|
|
}
|
|
}
|
|
|
|
relocs.push_back (reloc);
|
|
}
|
|
|
|
std::stable_sort (relocs.begin (), relocs.end (), reloc_offset_compare ());
|
|
}
|
|
}
|
|
|
|
file::file (const std::string& name, bool warnings)
|
|
: rhdr_len (0),
|
|
rhdr_length (0),
|
|
rhdr_version (0),
|
|
rhdr_checksum (0),
|
|
machine_rap_off (0),
|
|
machinetype (0),
|
|
datatype (0),
|
|
class_ (0),
|
|
layout_rap_off (0),
|
|
init_off (0),
|
|
fini_off (0),
|
|
strtab_rap_off (0),
|
|
strtab_size (0),
|
|
strtab (0),
|
|
symtab_rap_off (0),
|
|
symtab_size (0),
|
|
symtab (0),
|
|
relocs_rap_off (0),
|
|
relocs_size (0),
|
|
detail_rap_off (0),
|
|
obj_num (0),
|
|
obj_name (0),
|
|
sec_num (0),
|
|
rpath (0),
|
|
rpathlen (0),
|
|
str_detail (0),
|
|
warnings (warnings),
|
|
image (name)
|
|
{
|
|
for (int s = 0; s < rld::rap::rap_secs; ++s)
|
|
secs[s].name = rld::rap::section_name (s);
|
|
image.open ();
|
|
parse_header ();
|
|
}
|
|
|
|
file::~file ()
|
|
{
|
|
image.close ();
|
|
|
|
if (symtab)
|
|
delete [] symtab;
|
|
if (strtab)
|
|
delete [] strtab;
|
|
if (obj_name)
|
|
delete [] obj_name;
|
|
if (sec_num)
|
|
delete [] sec_num;
|
|
if (str_detail)
|
|
delete [] str_detail;
|
|
|
|
}
|
|
|
|
void
|
|
file::parse_header ()
|
|
{
|
|
std::string name = image.name ().full ();
|
|
|
|
char rhdr[64];
|
|
|
|
image.seek_read (0, (uint8_t*) rhdr, 64);
|
|
|
|
if ((rhdr[0] != 'R') || (rhdr[1] != 'A') || (rhdr[2] != 'P') || (rhdr[3] != ','))
|
|
throw rld::error ("Invalid RAP file", "open: " + name);
|
|
|
|
char* sptr = rhdr + 4;
|
|
char* eptr;
|
|
|
|
rhdr_length = ::strtoul (sptr, &eptr, 10);
|
|
|
|
if (*eptr != ',')
|
|
throw rld::error ("Cannot parse RAP header", "open: " + name);
|
|
|
|
sptr = eptr + 1;
|
|
|
|
rhdr_version = ::strtoul (sptr, &eptr, 10);
|
|
|
|
if (*eptr != ',')
|
|
throw rld::error ("Cannot parse RAP header", "open: " + name);
|
|
|
|
sptr = eptr + 1;
|
|
|
|
if ((sptr[0] == 'N') &&
|
|
(sptr[1] == 'O') &&
|
|
(sptr[2] == 'N') &&
|
|
(sptr[3] == 'E'))
|
|
{
|
|
rhdr_compression = "NONE";
|
|
eptr = sptr + 4;
|
|
}
|
|
else if ((sptr[0] == 'L') &&
|
|
(sptr[1] == 'Z') &&
|
|
(sptr[2] == '7') &&
|
|
(sptr[3] == '7'))
|
|
{
|
|
rhdr_compression = "LZ77";
|
|
eptr = sptr + 4;
|
|
}
|
|
else
|
|
throw rld::error ("Cannot parse RAP header", "open: " + name);
|
|
|
|
if (*eptr != ',')
|
|
throw rld::error ("Cannot parse RAP header", "open: " + name);
|
|
|
|
sptr = eptr + 1;
|
|
|
|
rhdr_checksum = ::strtoul (sptr, &eptr, 16);
|
|
|
|
if (*eptr != '\n')
|
|
throw rld::error ("Cannot parse RAP header", "open: " + name);
|
|
|
|
rhdr_len = eptr - rhdr + 1;
|
|
|
|
if (warnings && (rhdr_length != image.size ()))
|
|
std::cout << " warning: header length does not match file size: header="
|
|
<< rhdr_length
|
|
<< " file-size=" << image.size ()
|
|
<< std::endl;
|
|
|
|
header.insert (0, rhdr, rhdr_len);
|
|
|
|
image.seek (rhdr_len);
|
|
}
|
|
|
|
void
|
|
file::load_details (rld::compress::compressor& comp)
|
|
{
|
|
uint32_t tmp;
|
|
|
|
comp >> rpathlen;
|
|
|
|
obj_name = new uint8_t*[obj_num];
|
|
|
|
sec_num = new uint32_t[obj_num];
|
|
|
|
/* how many sections of each object file */
|
|
for (uint32_t i = 0; i < obj_num; i++)
|
|
{
|
|
comp >> tmp;
|
|
sec_num[i] = tmp;
|
|
}
|
|
|
|
/* strtable size */
|
|
comp >> tmp;
|
|
str_detail = new uint8_t[tmp];
|
|
if (comp.read (str_detail, tmp) != tmp)
|
|
throw rld::error ("Reading file str details error", "rapper");
|
|
|
|
if (rpathlen > 0)
|
|
rpath = (uint8_t*)str_detail;
|
|
else rpath = NULL;
|
|
|
|
section_detail sec;
|
|
|
|
for (uint32_t i = 0; i < obj_num; i++)
|
|
{
|
|
sec.obj = i;
|
|
for (uint32_t j = 0; j < sec_num[i]; j++)
|
|
{
|
|
comp >> sec.name;
|
|
comp >> tmp;
|
|
sec.offset = tmp & 0xfffffff;
|
|
sec.id = tmp >> 28;
|
|
comp >> sec.size;
|
|
|
|
sec_details.push_back (section_detail (sec));
|
|
}
|
|
}
|
|
}
|
|
void
|
|
file::load ()
|
|
{
|
|
image.seek (rhdr_len);
|
|
|
|
rld::compress::compressor comp (image, rap_comp_buffer, false);
|
|
|
|
/*
|
|
* uint32_t: machinetype
|
|
* uint32_t: datatype
|
|
* uint32_t: class
|
|
*/
|
|
machine_rap_off = comp.offset ();
|
|
comp >> machinetype
|
|
>> datatype
|
|
>> class_;
|
|
|
|
/*
|
|
* uint32_t: init
|
|
* uint32_t: fini
|
|
* uint32_t: symtab_size
|
|
* uint32_t: strtab_size
|
|
* uint32_t: relocs_size
|
|
*/
|
|
layout_rap_off = comp.offset ();
|
|
comp >> init_off
|
|
>> fini_off
|
|
>> symtab_size
|
|
>> strtab_size
|
|
>> relocs_size;
|
|
|
|
/*
|
|
* Load the file details.
|
|
*/
|
|
detail_rap_off = comp.offset ();
|
|
|
|
comp >> obj_num;
|
|
|
|
if (obj_num > 0)
|
|
load_details(comp);
|
|
|
|
/*
|
|
* uint32_t: text_size
|
|
* uint32_t: text_alignment
|
|
* uint32_t: const_size
|
|
* uint32_t: const_alignment
|
|
* uint32_t: ctor_size
|
|
* uint32_t: ctor_alignment
|
|
* uint32_t: dtor_size
|
|
* uint32_t: dtor_alignment
|
|
* uint32_t: data_size
|
|
* uint32_t: data_alignment
|
|
* uint32_t: bss_size
|
|
* uint32_t: bss_alignment
|
|
*/
|
|
for (int s = 0; s < rld::rap::rap_secs; ++s)
|
|
comp >> secs[s].size
|
|
>> secs[s].alignment;
|
|
|
|
/*
|
|
* Load sections.
|
|
*/
|
|
for (int s = 0; s < rld::rap::rap_secs; ++s)
|
|
if (s != rld::rap::rap_bss)
|
|
secs[s].load_data (comp);
|
|
|
|
/*
|
|
* Load the string table.
|
|
*/
|
|
strtab_rap_off = comp.offset ();
|
|
if (strtab_size)
|
|
{
|
|
strtab = new uint8_t[strtab_size];
|
|
if (comp.read (strtab, strtab_size) != strtab_size)
|
|
throw rld::error ("Reading string table failed", "rapper");
|
|
}
|
|
|
|
/*
|
|
* Load the symbol table.
|
|
*/
|
|
symtab_rap_off = comp.offset ();
|
|
if (symtab_size)
|
|
{
|
|
symtab = new uint8_t[symtab_size];
|
|
if (comp.read (symtab, symtab_size) != symtab_size)
|
|
throw rld::error ("Reading symbol table failed", "rapper");
|
|
}
|
|
|
|
/*
|
|
* Load the relocation tables.
|
|
*/
|
|
relocs_rap_off = comp.offset ();
|
|
for (int s = 0; s < rld::rap::rap_secs; ++s)
|
|
secs[s].load_relocs (comp);
|
|
}
|
|
|
|
void
|
|
file::expand ()
|
|
{
|
|
std::string name = image.name ().full ();
|
|
std::string extension = rld::path::extension (image.name ().full ());
|
|
|
|
name = name.substr (0, name.size () - extension.size ()) + ".xrap";
|
|
|
|
image.seek (rhdr_len);
|
|
|
|
rld::compress::compressor comp (image, rap_comp_buffer, false);
|
|
rld::files::image out (name);
|
|
|
|
out.open (true);
|
|
out.seek (0);
|
|
while (true)
|
|
{
|
|
if (comp.read (out, rap_comp_buffer) != rap_comp_buffer)
|
|
break;
|
|
}
|
|
out.close ();
|
|
}
|
|
|
|
const std::string
|
|
file::name () const
|
|
{
|
|
return image.name ().full ();
|
|
}
|
|
|
|
int
|
|
file::symbols () const
|
|
{
|
|
return symtab_size / (3 * sizeof (uint32_t));
|
|
}
|
|
|
|
void
|
|
file::symbol (int index, uint32_t& data, uint32_t& name, uint32_t& value) const
|
|
{
|
|
if (index < symbols ())
|
|
{
|
|
uint8_t* sym = symtab + (index * 3 * sizeof (uint32_t));
|
|
data = get_value < uint32_t > (sym);
|
|
name = get_value < uint32_t > (sym + (1 * sizeof (uint32_t)));
|
|
value = get_value < uint32_t > (symtab + (2 * sizeof (uint32_t)));
|
|
}
|
|
}
|
|
|
|
const char*
|
|
file::string (int index)
|
|
{
|
|
std::string name = image.name ().full ();
|
|
|
|
if (strtab_size == 0)
|
|
throw rld::error ("No string table", "string: " + name);
|
|
|
|
uint32_t offset = 0;
|
|
int count = 0;
|
|
while (offset < strtab_size)
|
|
{
|
|
if (count++ == index)
|
|
return (const char*) &strtab[offset];
|
|
offset = ::strlen ((const char*) &strtab[offset]) + 1;
|
|
}
|
|
|
|
throw rld::error ("Invalid string index", "string: " + name);
|
|
}
|
|
}
|
|
|
|
void
|
|
rap_show (rld::path::paths& raps,
|
|
bool warnings,
|
|
bool show_header,
|
|
bool show_machine,
|
|
bool show_layout,
|
|
bool show_strings,
|
|
bool show_symbols,
|
|
bool show_relocs,
|
|
bool show_details)
|
|
{
|
|
for (rld::path::paths::iterator pi = raps.begin();
|
|
pi != raps.end();
|
|
++pi)
|
|
{
|
|
std::cout << *pi << ':' << std::endl;
|
|
|
|
rap::file r (*pi, warnings);
|
|
|
|
try
|
|
{
|
|
r.load ();
|
|
}
|
|
catch (rld::error re)
|
|
{
|
|
std::cout << " error: "
|
|
<< re.where << ": " << re.what
|
|
<< std::endl
|
|
<< " warning: file read failed, some data may be corrupt or not present."
|
|
<< std::endl;
|
|
}
|
|
|
|
if (show_header)
|
|
{
|
|
std::cout << " Header:" << std::endl
|
|
<< " string: " << r.header
|
|
<< " length: " << r.rhdr_len << std::endl
|
|
<< " version: " << r.rhdr_version << std::endl
|
|
<< " compression: " << r.rhdr_compression << std::endl
|
|
<< std::hex << std::setfill ('0')
|
|
<< " checksum: " << std::setw (8) << r.rhdr_checksum << std::endl
|
|
<< std::dec << std::setfill(' ');
|
|
}
|
|
|
|
if (show_machine)
|
|
{
|
|
std::cout << " Machine: 0x"
|
|
<< std::hex << std::setfill ('0')
|
|
<< std::setw (8) << r.machine_rap_off
|
|
<< std::setfill (' ') << std::dec
|
|
<< " (" << r.machine_rap_off << ')' << std::endl
|
|
<< " machinetype: "<< r.machinetype << std::endl
|
|
<< " datatype: "<< r.datatype << std::endl
|
|
<< " class: "<< r.class_ << std::endl;
|
|
}
|
|
|
|
if (show_layout)
|
|
{
|
|
std::cout << " Layout: 0x"
|
|
<< std::hex << std::setfill ('0')
|
|
<< std::setw (8) << r.layout_rap_off
|
|
<< std::setfill (' ') << std::dec
|
|
<< " (" << r.layout_rap_off << ')' << std::endl
|
|
<< std::setw (18) << " "
|
|
<< " size align offset " << std::endl;
|
|
uint32_t relocs_size = 0;
|
|
for (int s = 0; s < rld::rap::rap_secs; ++s)
|
|
{
|
|
relocs_size += r.secs[s].relocs.size ();
|
|
std::cout << std::setw (16) << rld::rap::section_name (s)
|
|
<< ": " << std::setw (6) << r.secs[s].size
|
|
<< std::setw (7) << r.secs[s].alignment;
|
|
if (s != rld::rap::rap_bss)
|
|
std::cout << std::hex << std::setfill ('0')
|
|
<< " 0x" << std::setw (8) << r.secs[s].rap_off
|
|
<< std::setfill (' ') << std::dec
|
|
<< " (" << r.secs[s].rap_off << ')';
|
|
else
|
|
std::cout << " -";
|
|
std::cout << std::endl;
|
|
}
|
|
std::cout << std::setw (16) << "strtab" << ": "
|
|
<< std::setw (6) << r.strtab_size
|
|
<< std::setw (7) << '-'
|
|
<< std::hex << std::setfill ('0')
|
|
<< " 0x" << std::setw (8) << r.strtab_rap_off
|
|
<< std::setfill (' ') << std::dec
|
|
<< " (" << r.strtab_rap_off << ')' << std::endl
|
|
<< std::setw (16) << "symtab" << ": "
|
|
<< std::setw (6) << r.symtab_size
|
|
<< std::setw (7) << '-'
|
|
<< std::hex << std::setfill ('0')
|
|
<< " 0x" << std::setw (8) << r.symtab_rap_off
|
|
<< std::setfill (' ') << std::dec
|
|
<< " (" << r.symtab_rap_off << ')' << std::endl
|
|
<< std::setw (16) << "relocs" << ": "
|
|
<< std::setw (6) << (relocs_size * 3 * sizeof (uint32_t))
|
|
<< std::setw (7) << '-'
|
|
<< std::hex << std::setfill ('0')
|
|
<< " 0x" << std::setw (8) << r.relocs_rap_off
|
|
<< std::setfill (' ') << std::dec
|
|
<< " (" << r.relocs_rap_off << ')' << std::endl;
|
|
}
|
|
|
|
if (show_details)
|
|
{
|
|
std::cout << " Details: 0x"
|
|
<< std::hex << std::setfill ('0')
|
|
<< std::setw (8) << r.detail_rap_off
|
|
<< std::setfill (' ') << std::dec
|
|
<< " (" << r.detail_rap_off << ')' << std::endl;
|
|
|
|
uint32_t pos = 0;
|
|
if (r.rpath != NULL)
|
|
{
|
|
std::cout << " rpath:" << std::endl;
|
|
while (pos < r.rpathlen)
|
|
{
|
|
std::cout << " " << r.rpath + pos << std::endl;
|
|
pos = std::string ((char*)(r.rpath + pos)).length () + pos + 1;
|
|
}
|
|
}
|
|
|
|
if (r.obj_num == 0)
|
|
std::cout << " No details" << std::endl;
|
|
else
|
|
std::cout << ' ' << r.obj_num <<" Files" << std::endl;
|
|
|
|
for (uint32_t i = 0; i < r.obj_num; ++i)
|
|
{
|
|
r.obj_name[i] = (uint8_t*) &r.str_detail[pos];
|
|
pos += ::strlen ((char*) &r.str_detail[pos]) + 1;
|
|
}
|
|
|
|
for (uint32_t i = 0; i < r.obj_num; ++i)
|
|
{
|
|
std::cout << " File: " << r.obj_name[i] << std::endl;
|
|
|
|
for (rap::section_details::const_iterator sd = r.sec_details.begin ();
|
|
sd != r.sec_details.end ();
|
|
++sd)
|
|
{
|
|
rap::section_detail tmp = *sd;
|
|
if (tmp.obj == i)
|
|
{
|
|
std::cout << std::setw (12) << "name:"
|
|
<< std::setw (16) << (char*)&r.str_detail[tmp.name]
|
|
<< " rap_section:"<< std::setw (8)
|
|
<< rap::section_names[tmp.id]
|
|
<< std::hex << std::setfill ('0')
|
|
<< " offset:0x" << std::setw (8) << tmp.offset
|
|
<< " size:0x" << std::setw (8) << tmp.size << std::dec
|
|
<< std::setfill (' ') << std::endl;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (show_strings)
|
|
{
|
|
std::cout << " Strings: 0x"
|
|
<< std::hex << std::setfill ('0')
|
|
<< std::setw (8) << r.strtab_rap_off
|
|
<< std::setfill (' ') << std::dec
|
|
<< " (" << r.strtab_rap_off << ')'
|
|
<< " size: " << r.strtab_size
|
|
<< std::endl;
|
|
if (r.strtab_size)
|
|
{
|
|
uint32_t offset = 0;
|
|
int count = 0;
|
|
while (offset < r.strtab_size)
|
|
{
|
|
std::cout << std::setw (16) << count++
|
|
<< std::hex << std::setfill ('0')
|
|
<< " (0x" << std::setw (6) << offset << "): "
|
|
<< std::dec << std::setfill (' ')
|
|
<< (char*) &r.strtab[offset] << std::endl;
|
|
offset += ::strlen ((char*) &r.strtab[offset]) + 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::cout << std::setw (16) << " "
|
|
<< "No string table found." << std::endl;
|
|
}
|
|
}
|
|
|
|
if (show_symbols)
|
|
{
|
|
std::cout << " Symbols: 0x"
|
|
<< std::hex << std::setfill ('0')
|
|
<< std::setw (8) << r.symtab_rap_off
|
|
<< std::setfill (' ') << std::dec
|
|
<< " (" << r.symtab_rap_off << ')'
|
|
<< " size: " << r.symtab_size
|
|
<< std::endl;
|
|
if (r.symtab_size)
|
|
{
|
|
std::cout << std::setw (18) << " "
|
|
<< " data section value name" << std::endl;
|
|
for (int s = 0; s < r.symbols (); ++s)
|
|
{
|
|
uint32_t data;
|
|
uint32_t name;
|
|
uint32_t value;
|
|
r.symbol (s, data, name, value);
|
|
std::cout << std::setw (16) << s << ": "
|
|
<< std::hex << std::setfill ('0')
|
|
<< "0x" << std::setw (4) << (data & 0xffff)
|
|
<< std::dec << std::setfill (' ')
|
|
<< " " << std::setw (8) << rld::rap::section_name (data >> 16)
|
|
<< std::hex << std::setfill ('0')
|
|
<< " 0x" << std::setw(8) << value
|
|
<< " " << &r.strtab[name]
|
|
<< std::dec << std::setfill (' ')
|
|
<< std::endl;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::cout << std::setw (16) << " "
|
|
<< "No symbol table found." << std::endl;
|
|
}
|
|
}
|
|
|
|
if (show_relocs)
|
|
{
|
|
std::cout << " Relocations: 0x"
|
|
<< std::hex << std::setfill ('0')
|
|
<< std::setw (8) << r.relocs_rap_off
|
|
<< std::setfill (' ') << std::dec
|
|
<< " (" << r.relocs_rap_off << ')' << std::endl;
|
|
int count = 0;
|
|
for (int s = 0; s < rld::rap::rap_secs; ++s)
|
|
{
|
|
if (r.secs[s].relocs.size ())
|
|
{
|
|
const char* rela = r.secs[s].rela ? "(A)" : " ";
|
|
std::cout << std::setw (16) << r.secs[s].name
|
|
<< ": info offset addend "
|
|
<< rela
|
|
<< " symbol name" << std::endl;
|
|
for (size_t f = 0; f < r.secs[s].relocs.size (); ++f)
|
|
{
|
|
rap::relocation& reloc = r.secs[s].relocs[f];
|
|
std::cout << std::setw (16) << count++ << ": ";
|
|
reloc.output ();
|
|
std::cout << std::endl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
rap_overlay (rld::path::paths& raps, bool warnings)
|
|
{
|
|
std::cout << "Overlay .... " << std::endl;
|
|
for (rld::path::paths::iterator pi = raps.begin();
|
|
pi != raps.end();
|
|
++pi)
|
|
{
|
|
rap::file r (*pi, warnings);
|
|
std::cout << r.name () << std::endl;
|
|
|
|
r.load ();
|
|
|
|
for (int s = 0; s < rld::rap::rap_secs; ++s)
|
|
{
|
|
rap::section& sec = r.secs[s];
|
|
|
|
if (sec.size && sec.data)
|
|
{
|
|
std::cout << rld::rap::section_name (s) << ':' << std::endl;
|
|
|
|
size_t line_length = 16;
|
|
uint32_t offset = 0;
|
|
size_t reloc = 0;
|
|
|
|
while (offset < sec.size)
|
|
{
|
|
size_t length = sec.size - offset;
|
|
|
|
if (reloc < sec.relocs.size ())
|
|
length = sec.relocs[reloc].offset - offset;
|
|
|
|
if ((offset + length) < sec.size)
|
|
{
|
|
length += line_length;
|
|
length -= length % line_length;
|
|
}
|
|
|
|
rtems::utils::dump (sec.data + offset,
|
|
length,
|
|
sizeof (uint8_t),
|
|
false,
|
|
line_length,
|
|
offset);
|
|
|
|
const int indent = 8;
|
|
std::ostringstream line;
|
|
|
|
line << std::setw (indent) << ' ';
|
|
|
|
while ((reloc < sec.relocs.size ()) &&
|
|
(sec.relocs[reloc].offset >= offset) &&
|
|
(sec.relocs[reloc].offset < (offset + length)))
|
|
{
|
|
int spaces = ((((sec.relocs[reloc].offset + 1) % line_length) * 3) +
|
|
indent - 1);
|
|
|
|
spaces -= line.str ().size ();
|
|
|
|
line << std::setw (spaces) << " ^" << reloc
|
|
<< ':' << std::hex
|
|
<< sec.relocs[reloc].addend
|
|
<< std::dec;
|
|
|
|
++reloc;
|
|
}
|
|
|
|
std::cout << line.str () << std::endl;
|
|
|
|
offset += length;
|
|
}
|
|
|
|
if (sec.relocs.size ())
|
|
{
|
|
int count = 0;
|
|
std::cout << " info offset addend symbol name" << std::endl;
|
|
for (size_t f = 0; f < r.secs[s].relocs.size (); ++f)
|
|
{
|
|
rap::relocation& reloc = r.secs[s].relocs[f];
|
|
std::cout << std::setw (4) << count++ << ' ';
|
|
reloc.output ();
|
|
std::cout << std::endl;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
rap_expander (rld::path::paths& raps, bool warnings)
|
|
{
|
|
std::cout << "Expanding .... " << std::endl;
|
|
for (rld::path::paths::iterator pi = raps.begin();
|
|
pi != raps.end();
|
|
++pi)
|
|
{
|
|
rap::file r (*pi, warnings);
|
|
std::cout << ' ' << r.name () << std::endl;
|
|
r.expand ();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* RTEMS RAP options.
|
|
*/
|
|
static struct option rld_opts[] = {
|
|
{ "help", no_argument, NULL, 'h' },
|
|
{ "version", no_argument, NULL, 'V' },
|
|
{ "verbose", no_argument, NULL, 'v' },
|
|
{ "no-warn", no_argument, NULL, 'n' },
|
|
{ "all", no_argument, NULL, 'a' },
|
|
{ "header", no_argument, NULL, 'H' },
|
|
{ "machine", no_argument, NULL, 'm' },
|
|
{ "layout", no_argument, NULL, 'l' },
|
|
{ "strings", no_argument, NULL, 's' },
|
|
{ "symbols", no_argument, NULL, 'S' },
|
|
{ "relocs", no_argument, NULL, 'r' },
|
|
{ "overlay", no_argument, NULL, 'o' },
|
|
{ "expand", no_argument, NULL, 'x' },
|
|
{ NULL, 0, NULL, 0 }
|
|
};
|
|
|
|
void
|
|
usage (int exit_code)
|
|
{
|
|
std::cout << "rtems-rap [options] objects" << std::endl
|
|
<< "Options and arguments:" << std::endl
|
|
<< " -h : help (also --help)" << std::endl
|
|
<< " -V : print linker version number and exit (also --version)" << std::endl
|
|
<< " -v : verbose (trace import parts), can supply multiple times" << std::endl
|
|
<< " to increase verbosity (also --verbose)" << std::endl
|
|
<< " -n : no warnings (also --no-warn)" << std::endl
|
|
<< " -a : show all (also --all)" << std::endl
|
|
<< " -H : show header (also --header)" << std::endl
|
|
<< " -m : show machine details (also --machine)" << std::endl
|
|
<< " -l : show layout (also --layout)" << std::endl
|
|
<< " -s : show strings (also --strings)" << std::endl
|
|
<< " -S : show symbols (also --symbols)" << std::endl
|
|
<< " -r : show relocations (also --relocs)" << std::endl
|
|
<< " -o : linkage overlay (also --overlay)" << std::endl
|
|
<< " -x : expand (also --expand)" << std::endl
|
|
<< " -f : show file details" << std::endl;
|
|
::exit (exit_code);
|
|
}
|
|
|
|
static void
|
|
fatal_signal (int signum)
|
|
{
|
|
signal (signum, SIG_DFL);
|
|
|
|
rld::process::temporaries_clean_up ();
|
|
|
|
/*
|
|
* Get the same signal again, this time not handled, so its normal effect
|
|
* occurs.
|
|
*/
|
|
kill (getpid (), signum);
|
|
}
|
|
|
|
static void
|
|
setup_signals (void)
|
|
{
|
|
if (signal (SIGINT, SIG_IGN) != SIG_IGN)
|
|
signal (SIGINT, fatal_signal);
|
|
#ifdef SIGHUP
|
|
if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
|
|
signal (SIGHUP, fatal_signal);
|
|
#endif
|
|
if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
|
|
signal (SIGTERM, fatal_signal);
|
|
#ifdef SIGPIPE
|
|
if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
|
|
signal (SIGPIPE, fatal_signal);
|
|
#endif
|
|
#ifdef SIGCHLD
|
|
signal (SIGCHLD, SIG_DFL);
|
|
#endif
|
|
}
|
|
|
|
int
|
|
main (int argc, char* argv[])
|
|
{
|
|
int ec = 0;
|
|
|
|
setup_signals ();
|
|
|
|
try
|
|
{
|
|
rld::path::paths raps;
|
|
bool warnings = true;
|
|
bool show = false;
|
|
bool show_header = false;
|
|
bool show_machine = false;
|
|
bool show_layout = false;
|
|
bool show_strings = false;
|
|
bool show_symbols = false;
|
|
bool show_relocs = false;
|
|
bool show_details = false;
|
|
bool overlay = false;
|
|
bool expand = false;
|
|
|
|
while (true)
|
|
{
|
|
int opt = ::getopt_long (argc, argv, "hvVnaHmlsSroxf", rld_opts, NULL);
|
|
if (opt < 0)
|
|
break;
|
|
|
|
switch (opt)
|
|
{
|
|
case 'V':
|
|
std::cout << "rtems-rap (RTEMS RAP Manager) " << rld::version ()
|
|
<< ", RTEMS revision " << rld::rtems::version ()
|
|
<< std::endl;
|
|
::exit (0);
|
|
break;
|
|
|
|
case 'v':
|
|
rld::verbose_inc ();
|
|
break;
|
|
|
|
case 'n':
|
|
warnings = false;
|
|
break;
|
|
|
|
case 'a':
|
|
show = true;
|
|
show_header = true;
|
|
show_machine = true;
|
|
show_layout = true;
|
|
show_strings = true;
|
|
show_symbols = true;
|
|
show_relocs = true;
|
|
show_details = true;
|
|
break;
|
|
|
|
case 'H':
|
|
show = true;
|
|
show_header = true;
|
|
break;
|
|
|
|
case 'm':
|
|
show = true;
|
|
show_machine = true;
|
|
break;
|
|
|
|
case 'l':
|
|
show = true;
|
|
show_layout = true;
|
|
break;
|
|
|
|
case 's':
|
|
show = true;
|
|
show_strings = true;
|
|
break;
|
|
|
|
case 'S':
|
|
show = true;
|
|
show_symbols = true;
|
|
break;
|
|
|
|
case 'r':
|
|
show = true;
|
|
show_relocs = true;
|
|
break;
|
|
|
|
case 'o':
|
|
overlay = true;
|
|
break;
|
|
|
|
case 'x':
|
|
expand = true;
|
|
break;
|
|
|
|
case 'f':
|
|
show_details = true;
|
|
break;
|
|
|
|
case '?':
|
|
case 'h':
|
|
usage (0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
std::cout << "RTEMS RAP " << rld::version () << std::endl << std::endl;
|
|
|
|
/*
|
|
* If there are no RAP files so there is nothing to do.
|
|
*/
|
|
if (argc == 0)
|
|
throw rld::error ("no RAP files", "options");
|
|
|
|
/*
|
|
* Load the remaining command line arguments into a container.
|
|
*/
|
|
while (argc--)
|
|
raps.push_back (*argv++);
|
|
|
|
if (show)
|
|
rap_show (raps,
|
|
warnings,
|
|
show_header,
|
|
show_machine,
|
|
show_layout,
|
|
show_strings,
|
|
show_symbols,
|
|
show_relocs,
|
|
show_details);
|
|
|
|
if (overlay)
|
|
rap_overlay (raps, warnings);
|
|
|
|
if (expand)
|
|
rap_expander (raps, warnings);
|
|
}
|
|
catch (rld::error re)
|
|
{
|
|
std::cerr << "error: "
|
|
<< re.where << ": " << re.what
|
|
<< std::endl;
|
|
ec = 10;
|
|
}
|
|
catch (std::exception& e)
|
|
{
|
|
int status;
|
|
char* realname;
|
|
realname = abi::__cxa_demangle (e.what(), 0, 0, &status);
|
|
std::cerr << "error: exception: " << realname << " [";
|
|
::free (realname);
|
|
const std::type_info &ti = typeid (e);
|
|
realname = abi::__cxa_demangle (ti.name(), 0, 0, &status);
|
|
std::cerr << realname << "] " << e.what () << std::endl;
|
|
::free (realname);
|
|
ec = 11;
|
|
}
|
|
catch (...)
|
|
{
|
|
/*
|
|
* Helps to know if this happens.
|
|
*/
|
|
std::cout << "error: unhandled exception" << std::endl;
|
|
ec = 12;
|
|
}
|
|
|
|
return ec;
|
|
}
|