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