|
1 /* |
|
2 gelftrans.c - gelf_* translation functions. |
|
3 Copyright (C) 2000 - 2001 Michael Riepe |
|
4 |
|
5 This library is free software; you can redistribute it and/or |
|
6 modify it under the terms of the GNU Library General Public |
|
7 License as published by the Free Software Foundation; either |
|
8 version 2 of the License, or (at your option) any later version. |
|
9 |
|
10 This library is distributed in the hope that it will be useful, |
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
13 Library General Public License for more details. |
|
14 |
|
15 You should have received a copy of the GNU Library General Public |
|
16 License along with this library; if not, write to the Free Software |
|
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
18 */ |
|
19 |
|
20 #include <private.h> |
|
21 |
|
22 #if __LIBELF64 |
|
23 |
|
24 #ifndef lint |
|
25 static const char rcsid[] = "@(#) $Id: gelftrans.c,v 1.9 2005/05/21 15:39:23 michael Exp $"; |
|
26 #endif /* lint */ |
|
27 |
|
28 #define check_and_copy(type, d, s, name, eret) \ |
|
29 do { \ |
|
30 if (sizeof((d)->name) < sizeof((s)->name) \ |
|
31 && (type)(s)->name != (s)->name) { \ |
|
32 seterr(ERROR_BADVALUE); \ |
|
33 return (eret); \ |
|
34 } \ |
|
35 (d)->name = (type)(s)->name; \ |
|
36 } while (0) |
|
37 |
|
38 /* |
|
39 * These macros are missing on some Linux systems |
|
40 */ |
|
41 #if !defined(ELF32_R_SYM) || !defined(ELF32_R_TYPE) || !defined(ELF32_R_INFO) |
|
42 # undef ELF32_R_SYM |
|
43 # undef ELF32_R_TYPE |
|
44 # undef ELF32_R_INFO |
|
45 # define ELF32_R_SYM(i) ((i)>>8) |
|
46 # define ELF32_R_TYPE(i) ((unsigned char)(i)) |
|
47 # define ELF32_R_INFO(s,t) (((s)<<8)+(unsigned char)(t)) |
|
48 #endif /* !defined(...) */ |
|
49 |
|
50 #if !defined(ELF64_R_SYM) || !defined(ELF64_R_TYPE) || !defined(ELF64_R_INFO) |
|
51 # undef ELF64_R_SYM |
|
52 # undef ELF64_R_TYPE |
|
53 # undef ELF64_R_INFO |
|
54 # define ELF64_R_SYM(i) ((i)>>32) |
|
55 # define ELF64_R_TYPE(i) ((i)&0xffffffffL) |
|
56 # define ELF64_R_INFO(s,t) (((Elf64_Xword)(s)<<32)+((t)&0xffffffffL)) |
|
57 #endif /* !defined(...) */ |
|
58 |
|
59 static char* |
|
60 get_addr_and_class(const Elf_Data *data, int ndx, Elf_Type type, unsigned *cls) { |
|
61 Scn_Data *sd = (Scn_Data*)data; |
|
62 Elf_Scn *scn; |
|
63 Elf *elf; |
|
64 size_t n; |
|
65 |
|
66 if (!sd) { |
|
67 return NULL; |
|
68 } |
|
69 elf_assert(sd->sd_magic == DATA_MAGIC); |
|
70 scn = sd->sd_scn; |
|
71 elf_assert(scn); |
|
72 elf_assert(scn->s_magic == SCN_MAGIC); |
|
73 elf = scn->s_elf; |
|
74 elf_assert(elf); |
|
75 elf_assert(elf->e_magic == ELF_MAGIC); |
|
76 if (elf->e_kind != ELF_K_ELF) { |
|
77 seterr(ERROR_NOTELF); |
|
78 return NULL; |
|
79 } |
|
80 if (!valid_class(elf->e_class)) { |
|
81 seterr(ERROR_UNKNOWN_CLASS); |
|
82 return NULL; |
|
83 } |
|
84 if (data->d_type != type) { |
|
85 seterr(ERROR_BADTYPE); |
|
86 return NULL; |
|
87 } |
|
88 n = _msize(elf->e_class, data->d_version, type); |
|
89 if (n == 0) { |
|
90 seterr(ERROR_UNIMPLEMENTED); |
|
91 return NULL; |
|
92 } |
|
93 if (ndx < 0 || data->d_size < (ndx + 1) * n) { |
|
94 seterr(ERROR_BADINDEX); |
|
95 return NULL; |
|
96 } |
|
97 if (!data->d_buf) { |
|
98 seterr(ERROR_NULLBUF); |
|
99 return NULL; |
|
100 } |
|
101 if (cls) { |
|
102 *cls = elf->e_class; |
|
103 } |
|
104 return (char*)data->d_buf + n * ndx; |
|
105 } |
|
106 |
|
107 GElf_Sym* |
|
108 gelf_getsym(Elf_Data *src, int ndx, GElf_Sym *dst) { |
|
109 GElf_Sym buf; |
|
110 unsigned cls; |
|
111 char *tmp; |
|
112 |
|
113 if (!dst) { |
|
114 dst = &buf; |
|
115 } |
|
116 tmp = get_addr_and_class(src, ndx, ELF_T_SYM, &cls); |
|
117 if (!tmp) { |
|
118 return NULL; |
|
119 } |
|
120 if (cls == ELFCLASS64) { |
|
121 *dst = *(Elf64_Sym*)tmp; |
|
122 } |
|
123 else if (cls == ELFCLASS32) { |
|
124 Elf32_Sym *src = (Elf32_Sym*)tmp; |
|
125 |
|
126 check_and_copy(GElf_Word, dst, src, st_name, NULL); |
|
127 check_and_copy(unsigned char, dst, src, st_info, NULL); |
|
128 check_and_copy(unsigned char, dst, src, st_other, NULL); |
|
129 check_and_copy(GElf_Half, dst, src, st_shndx, NULL); |
|
130 check_and_copy(GElf_Addr, dst, src, st_value, NULL); |
|
131 check_and_copy(GElf_Xword, dst, src, st_size, NULL); |
|
132 } |
|
133 else { |
|
134 seterr(ERROR_UNIMPLEMENTED); |
|
135 return NULL; |
|
136 } |
|
137 if (dst == &buf) { |
|
138 dst = (GElf_Sym*)malloc(sizeof(GElf_Sym)); |
|
139 if (!dst) { |
|
140 seterr(ERROR_MEM_SYM); |
|
141 return NULL; |
|
142 } |
|
143 *dst = buf; |
|
144 } |
|
145 return dst; |
|
146 } |
|
147 |
|
148 int |
|
149 gelf_update_sym(Elf_Data *dst, int ndx, GElf_Sym *src) { |
|
150 unsigned cls; |
|
151 char *tmp; |
|
152 |
|
153 tmp = get_addr_and_class(dst, ndx, ELF_T_SYM, &cls); |
|
154 if (!tmp) { |
|
155 return 0; |
|
156 } |
|
157 if (cls == ELFCLASS64) { |
|
158 *(Elf64_Sym*)tmp = *src; |
|
159 } |
|
160 else if (cls == ELFCLASS32) { |
|
161 Elf32_Sym *dst = (Elf32_Sym*)tmp; |
|
162 |
|
163 check_and_copy(Elf32_Word, dst, src, st_name, 0); |
|
164 check_and_copy(Elf32_Addr, dst, src, st_value, 0); |
|
165 check_and_copy(Elf32_Word, dst, src, st_size, 0); |
|
166 check_and_copy(unsigned char, dst, src, st_info, 0); |
|
167 check_and_copy(unsigned char, dst, src, st_other, 0); |
|
168 check_and_copy(Elf32_Half, dst, src, st_shndx, 0); |
|
169 } |
|
170 else { |
|
171 seterr(ERROR_UNIMPLEMENTED); |
|
172 return 0; |
|
173 } |
|
174 return 1; |
|
175 } |
|
176 |
|
177 GElf_Dyn* |
|
178 gelf_getdyn(Elf_Data *src, int ndx, GElf_Dyn *dst) { |
|
179 GElf_Dyn buf; |
|
180 unsigned cls; |
|
181 char *tmp; |
|
182 |
|
183 if (!dst) { |
|
184 dst = &buf; |
|
185 } |
|
186 tmp = get_addr_and_class(src, ndx, ELF_T_DYN, &cls); |
|
187 if (!tmp) { |
|
188 return NULL; |
|
189 } |
|
190 if (cls == ELFCLASS64) { |
|
191 *dst = *(Elf64_Dyn*)tmp; |
|
192 } |
|
193 else if (cls == ELFCLASS32) { |
|
194 Elf32_Dyn *src = (Elf32_Dyn*)tmp; |
|
195 |
|
196 check_and_copy(GElf_Sxword, dst, src, d_tag, NULL); |
|
197 check_and_copy(GElf_Xword, dst, src, d_un.d_val, NULL); |
|
198 } |
|
199 else { |
|
200 seterr(ERROR_UNIMPLEMENTED); |
|
201 return NULL; |
|
202 } |
|
203 if (dst == &buf) { |
|
204 dst = (GElf_Dyn*)malloc(sizeof(GElf_Dyn)); |
|
205 if (!dst) { |
|
206 seterr(ERROR_MEM_DYN); |
|
207 return NULL; |
|
208 } |
|
209 *dst = buf; |
|
210 } |
|
211 return dst; |
|
212 } |
|
213 |
|
214 int |
|
215 gelf_update_dyn(Elf_Data *dst, int ndx, GElf_Dyn *src) { |
|
216 unsigned cls; |
|
217 char *tmp; |
|
218 |
|
219 tmp = get_addr_and_class(dst, ndx, ELF_T_DYN, &cls); |
|
220 if (!tmp) { |
|
221 return 0; |
|
222 } |
|
223 if (cls == ELFCLASS64) { |
|
224 *(Elf64_Dyn*)tmp = *src; |
|
225 } |
|
226 else if (cls == ELFCLASS32) { |
|
227 Elf32_Dyn *dst = (Elf32_Dyn*)tmp; |
|
228 |
|
229 check_and_copy(Elf32_Sword, dst, src, d_tag, 0); |
|
230 check_and_copy(Elf32_Word, dst, src, d_un.d_val, 0); |
|
231 } |
|
232 else { |
|
233 seterr(ERROR_UNIMPLEMENTED); |
|
234 return 0; |
|
235 } |
|
236 return 1; |
|
237 } |
|
238 |
|
239 GElf_Rela* |
|
240 gelf_getrela(Elf_Data *src, int ndx, GElf_Rela *dst) { |
|
241 GElf_Rela buf; |
|
242 unsigned cls; |
|
243 char *tmp; |
|
244 |
|
245 if (!dst) { |
|
246 dst = &buf; |
|
247 } |
|
248 tmp = get_addr_and_class(src, ndx, ELF_T_RELA, &cls); |
|
249 if (!tmp) { |
|
250 return NULL; |
|
251 } |
|
252 if (cls == ELFCLASS64) { |
|
253 *dst = *(Elf64_Rela*)tmp; |
|
254 } |
|
255 else if (cls == ELFCLASS32) { |
|
256 Elf32_Rela *src = (Elf32_Rela*)tmp; |
|
257 |
|
258 check_and_copy(GElf_Addr, dst, src, r_offset, NULL); |
|
259 dst->r_info = ELF64_R_INFO((Elf64_Xword)ELF32_R_SYM(src->r_info), |
|
260 (Elf64_Xword)ELF32_R_TYPE(src->r_info)); |
|
261 check_and_copy(GElf_Sxword, dst, src, r_addend, NULL); |
|
262 } |
|
263 else { |
|
264 seterr(ERROR_UNIMPLEMENTED); |
|
265 return NULL; |
|
266 } |
|
267 if (dst == &buf) { |
|
268 dst = (GElf_Rela*)malloc(sizeof(GElf_Rela)); |
|
269 if (!dst) { |
|
270 seterr(ERROR_MEM_RELA); |
|
271 return NULL; |
|
272 } |
|
273 *dst = buf; |
|
274 } |
|
275 return dst; |
|
276 } |
|
277 |
|
278 int |
|
279 gelf_update_rela(Elf_Data *dst, int ndx, GElf_Rela *src) { |
|
280 unsigned cls; |
|
281 char *tmp; |
|
282 |
|
283 tmp = get_addr_and_class(dst, ndx, ELF_T_RELA, &cls); |
|
284 if (!tmp) { |
|
285 return 0; |
|
286 } |
|
287 if (cls == ELFCLASS64) { |
|
288 *(Elf64_Rela*)tmp = *src; |
|
289 } |
|
290 else if (cls == ELFCLASS32) { |
|
291 Elf32_Rela *dst = (Elf32_Rela*)tmp; |
|
292 |
|
293 check_and_copy(Elf32_Addr, dst, src, r_offset, 0); |
|
294 if (ELF64_R_SYM(src->r_info) > 0xffffffUL |
|
295 || ELF64_R_TYPE(src->r_info) > 0xffUL) { |
|
296 seterr(ERROR_BADVALUE); |
|
297 return 0; |
|
298 } |
|
299 dst->r_info = ELF32_R_INFO((Elf32_Word)ELF64_R_SYM(src->r_info), |
|
300 (Elf32_Word)ELF64_R_TYPE(src->r_info)); |
|
301 check_and_copy(Elf32_Sword, dst, src, r_addend, 0); |
|
302 } |
|
303 else { |
|
304 seterr(ERROR_UNIMPLEMENTED); |
|
305 return 0; |
|
306 } |
|
307 return 1; |
|
308 } |
|
309 |
|
310 GElf_Rel* |
|
311 gelf_getrel(Elf_Data *src, int ndx, GElf_Rel *dst) { |
|
312 GElf_Rel buf; |
|
313 unsigned cls; |
|
314 char *tmp; |
|
315 |
|
316 if (!dst) { |
|
317 dst = &buf; |
|
318 } |
|
319 tmp = get_addr_and_class(src, ndx, ELF_T_REL, &cls); |
|
320 if (!tmp) { |
|
321 return NULL; |
|
322 } |
|
323 if (cls == ELFCLASS64) { |
|
324 *dst = *(Elf64_Rel*)tmp; |
|
325 } |
|
326 else if (cls == ELFCLASS32) { |
|
327 Elf32_Rel *src = (Elf32_Rel*)tmp; |
|
328 |
|
329 check_and_copy(GElf_Addr, dst, src, r_offset, NULL); |
|
330 dst->r_info = ELF64_R_INFO((Elf64_Xword)ELF32_R_SYM(src->r_info), |
|
331 (Elf64_Xword)ELF32_R_TYPE(src->r_info)); |
|
332 } |
|
333 else { |
|
334 seterr(ERROR_UNIMPLEMENTED); |
|
335 return NULL; |
|
336 } |
|
337 if (dst == &buf) { |
|
338 dst = (GElf_Rel*)malloc(sizeof(GElf_Rel)); |
|
339 if (!dst) { |
|
340 seterr(ERROR_MEM_REL); |
|
341 return NULL; |
|
342 } |
|
343 *dst = buf; |
|
344 } |
|
345 return dst; |
|
346 } |
|
347 |
|
348 int |
|
349 gelf_update_rel(Elf_Data *dst, int ndx, GElf_Rel *src) { |
|
350 unsigned cls; |
|
351 char *tmp; |
|
352 |
|
353 tmp = get_addr_and_class(dst, ndx, ELF_T_REL, &cls); |
|
354 if (!tmp) { |
|
355 return 0; |
|
356 } |
|
357 if (cls == ELFCLASS64) { |
|
358 *(Elf64_Rel*)tmp = *src; |
|
359 } |
|
360 else if (cls == ELFCLASS32) { |
|
361 Elf32_Rel *dst = (Elf32_Rel*)tmp; |
|
362 |
|
363 check_and_copy(Elf32_Addr, dst, src, r_offset, 0); |
|
364 if (ELF64_R_SYM(src->r_info) > 0xffffffUL |
|
365 || ELF64_R_TYPE(src->r_info) > 0xffUL) { |
|
366 seterr(ERROR_BADVALUE); |
|
367 return 0; |
|
368 } |
|
369 dst->r_info = ELF32_R_INFO((Elf32_Word)ELF64_R_SYM(src->r_info), |
|
370 (Elf32_Word)ELF64_R_TYPE(src->r_info)); |
|
371 } |
|
372 else { |
|
373 seterr(ERROR_UNIMPLEMENTED); |
|
374 return 0; |
|
375 } |
|
376 return 1; |
|
377 } |
|
378 |
|
379 #if 0 |
|
380 |
|
381 GElf_Syminfo* |
|
382 gelf_getsyminfo(Elf_Data *src, int ndx, GElf_Syminfo *dst) { |
|
383 seterr(ERROR_UNIMPLEMENTED); |
|
384 return NULL; |
|
385 } |
|
386 |
|
387 int |
|
388 gelf_update_syminfo(Elf_Data *dst, int ndx, GElf_Syminfo *src) { |
|
389 seterr(ERROR_UNIMPLEMENTED); |
|
390 return 0; |
|
391 } |
|
392 |
|
393 GElf_Move* |
|
394 gelf_getmove(Elf_Data *src, int ndx, GElf_Move *src) { |
|
395 seterr(ERROR_UNIMPLEMENTED); |
|
396 return NULL; |
|
397 } |
|
398 |
|
399 int |
|
400 gelf_update_move(Elf_Data *dst, int ndx, GElf_Move *src) { |
|
401 seterr(ERROR_UNIMPLEMENTED); |
|
402 return 0; |
|
403 } |
|
404 |
|
405 #endif |
|
406 |
|
407 #endif /* __LIBELF64 */ |