bintools/checklib/library/library.cpp
changeset 0 044383f39525
equal deleted inserted replaced
-1:000000000000 0:044383f39525
       
     1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Class for reading libraries in Unix "ar" format.
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "library.h"
       
    19 
       
    20 #include "misc/endian.h" // For misc::reverse_bytes()
       
    21 
       
    22 #include <fstream>
       
    23 #include <stdexcept>
       
    24 #include <cassert>
       
    25 #include <iostream>
       
    26 #include <iomanip>
       
    27 #include <cstdlib>
       
    28 
       
    29 namespace
       
    30 {
       
    31     // An ar library begins with this string.
       
    32     const char MAGIC[] = "!<arch>\n";
       
    33 
       
    34     // The size of an object header.
       
    35     const int HEADER_LENGTH = 60;
       
    36 
       
    37     // Each object *header* has this trailer.
       
    38     const char TRAILER[] = "`\n";
       
    39 }
       
    40 
       
    41 
       
    42 Library::Library(const char a_file_name[])
       
    43 {
       
    44     std::ifstream file(a_file_name, std::ios::in | std::ios::binary | std::ios::ate);
       
    45 
       
    46     if ( ! file.is_open() )
       
    47     {
       
    48         throw std::runtime_error("couldn't open file");
       
    49     }
       
    50 
       
    51     unsigned size  = file.tellg();
       
    52     m_mem_p = new char[size];
       
    53 
       
    54     file.seekg(0, std::ios::beg);
       
    55     file.read( const_cast<char*>(m_mem_p), size );
       
    56 
       
    57     file.close();
       
    58 
       
    59     const char* p1 = m_mem_p;
       
    60     const char* p2 = p1 + size - 1;
       
    61 
       
    62     // Eat all meta objects.
       
    63 
       
    64     p1 = _eat_ar_header(p1, p2);
       
    65     p1 = _eat_sym_table(p1, p2);
       
    66     p1 = _eat_junk_objs(p1, p2);
       
    67 
       
    68     m_first_p = p1; // Pointer to the start of the first "real" object.
       
    69     m_last_p = p2;  // Pointer to end of the last real object.
       
    70 }
       
    71 
       
    72 Library::~Library()
       
    73 {
       
    74     delete[] m_mem_p;
       
    75 }
       
    76 
       
    77 bool Library::contains_symbol(const char a_sym_name[]) const
       
    78 {
       
    79     std::vector<const char*>::const_iterator p = m_symbols.begin();
       
    80     std::vector<const char*>::const_iterator end_p = m_symbols.end();
       
    81 
       
    82     for ( ; p != end_p; ++p)
       
    83     {
       
    84         if ( std::strcmp(a_sym_name, *p) == 0 ) return 1;
       
    85     }
       
    86 
       
    87     return 0;
       
    88 }
       
    89 
       
    90 const std::vector< std::pair<const char*, const char*> >* Library::get_objects() const
       
    91 {
       
    92     if ( m_objects.empty() )
       
    93     {
       
    94         const char* p = m_first_p;
       
    95 
       
    96         unsigned long size;
       
    97 
       
    98         while (p < m_last_p)
       
    99         {
       
   100             p = _eat_obj_header(p, m_last_p, &size);
       
   101 
       
   102             m_objects.push_back( std::pair<const char*, const char*>(p, p + size) );
       
   103 
       
   104             p += size;
       
   105         }
       
   106     }
       
   107 
       
   108     return &m_objects;
       
   109 }
       
   110 
       
   111 const char* Library::_eat_ar_header(const char* p1, const char* p2) const
       
   112 {
       
   113     int magic_length = std::strlen(MAGIC);
       
   114 
       
   115     if (p2 - p1 + 1 < magic_length)
       
   116     {
       
   117         throw std::runtime_error("library too small for magic word");
       
   118     }
       
   119 
       
   120     if ( std::strncmp(p1, MAGIC, magic_length) != 0 )
       
   121     {
       
   122         throw std::runtime_error("bad magic; this is not a valid library");
       
   123     }
       
   124 
       
   125     return (p1 + magic_length);
       
   126 }
       
   127 
       
   128 const char* Library::_eat_sym_table(const char* a_first_p, const char* a_last_p) const
       
   129 {
       
   130     unsigned long obj_size;
       
   131 
       
   132     const char* p = _eat_obj_header(a_first_p, a_last_p, &obj_size, "/               "); // Read the header of the symbol table.
       
   133 
       
   134     if (p == a_first_p)
       
   135     {
       
   136         throw std::runtime_error("no library symbol table found");
       
   137     }
       
   138 
       
   139     const char* obj_end_p = p + obj_size;
       
   140 
       
   141     // Check that we're 4-byte aligned.
       
   142     assert( (reinterpret_cast<int>(p) & 0x3) == 0 );
       
   143 
       
   144     uint32_t nr_of_syms = *reinterpret_cast<const int*>(p);
       
   145     nr_of_syms = misc::reverse_bytes(nr_of_syms);
       
   146 
       
   147     p += sizeof(nr_of_syms);            // Go past the integer we just read.
       
   148     p += nr_of_syms * sizeof(uint32_t); // Go past all the offsets.
       
   149 
       
   150     unsigned n = 0;
       
   151 
       
   152     while (n < nr_of_syms && p < a_last_p)
       
   153     {
       
   154         m_symbols.push_back(p);
       
   155 
       
   156         p += std::strlen(p) + 1; 
       
   157 
       
   158         n++;
       
   159     }
       
   160 
       
   161     if (n != nr_of_syms)
       
   162     {
       
   163         throw std::runtime_error("inconsistent symbol table");
       
   164     }
       
   165 
       
   166     if (p > obj_end_p)
       
   167     {
       
   168         throw std::runtime_error("over-running symbol table");
       
   169     }
       
   170 
       
   171     return obj_end_p;
       
   172 }
       
   173 
       
   174 const char* Library::_eat_junk_objs(const char* p1, const char* p2) const
       
   175 {
       
   176     unsigned long obj_size;
       
   177     const char* p;
       
   178 
       
   179     p = _eat_obj_header(p1, p2, &obj_size, "//              ");
       
   180 
       
   181     if (p > p1)
       
   182     {
       
   183         p1 = p + obj_size;
       
   184     }
       
   185 
       
   186     p = _eat_obj_header(p1, p2, &obj_size, "/               ");
       
   187 
       
   188     if (p > p1)
       
   189     {
       
   190         p1 = p + obj_size;
       
   191     }
       
   192 
       
   193     p = _eat_obj_header(p1, p2, &obj_size, "//              ");
       
   194 
       
   195     if (p > p1)
       
   196     {
       
   197         p1 = p + obj_size;
       
   198     }
       
   199 
       
   200     return p1;
       
   201 }
       
   202 
       
   203 const char* Library::_eat_obj_header(const char* a_first_p, const char* a_last_p, unsigned long* a_size_p, const char* a_name) const
       
   204 {
       
   205     const char* p = a_first_p;
       
   206 
       
   207     // The header is 2-byte aligned, so ignore the previous object's trailing
       
   208     // padding byte.
       
   209     if ( reinterpret_cast<int>(p) & 1)
       
   210     {
       
   211         p++;
       
   212     }
       
   213 
       
   214     if (a_last_p - p + 1 < HEADER_LENGTH)
       
   215     {
       
   216         throw std::runtime_error("no space for library object header");
       
   217     }
       
   218 
       
   219     // At the moment We can only handle short names. This is enough for identifying
       
   220     // the meta objects "/" (symbol table) and "//" (object table).
       
   221 
       
   222     if ( a_name && std::strncmp(p, a_name, std::strlen(a_name)) != 0 )
       
   223     {
       
   224         return a_first_p;
       
   225     }
       
   226 
       
   227     p += 16; // Ignore the name field.
       
   228     p += 12; // Ignore the modification time.
       
   229     p +=  6; // Ignore the group ID.
       
   230     p +=  6; // Ignore the user ID.
       
   231     p +=  8; // Ignore the file mode.
       
   232 
       
   233     // Read the object size.
       
   234 
       
   235     if (a_size_p)
       
   236     {
       
   237         char* tail_p;
       
   238         *a_size_p = std::strtoul(p, &tail_p, 0);
       
   239 
       
   240         if (tail_p == p || tail_p > a_last_p + 1)
       
   241         {
       
   242             throw std::runtime_error("could not read library object size");
       
   243         }
       
   244     }
       
   245 
       
   246     p += 10; // Jump over the object size field.
       
   247 
       
   248     // Verify that the header trailer is correct.
       
   249 
       
   250     int trailer_length = std::strlen(TRAILER);
       
   251 
       
   252     if ( std::strncmp(p, TRAILER, trailer_length) != 0  )
       
   253     {
       
   254         throw std::runtime_error("incorrect library object header trailer");
       
   255     }
       
   256 
       
   257     return (p + trailer_length);
       
   258 }
       
   259 
       
   260