Elfutils fiddles fo fix striptofile.
[platform/upstream/rpm.git] / tools / sections.c
1 /* Needed for libelf */
2 #define _FILE_OFFSET_BITS 64
3
4 #include "system.h"
5
6 #include "sections.h"
7 #include "utils.h"
8
9 #include "debug.h"
10
11 typedef struct {
12   Elf32_Word debug_section; 
13   Elf32_Word name; 
14   Elf32_Off orig_offset;
15 } UnstripInfoSection32;
16
17 typedef struct {
18   Elf64_Word debug_section; 
19   Elf64_Word name; 
20   Elf64_Off orig_offset;
21 } UnstripInfoSection64;
22
23 typedef struct {
24   Elf32_Off orig_e_shoff;
25   Elf32_Off n_sections;
26   UnstripInfoSection32 sections[1];
27 } UnstripInfo32;
28
29 typedef struct {
30   Elf64_Off orig_e_shoff;
31   Elf64_Off n_sections;
32   UnstripInfoSection64 sections[1];
33 } UnstripInfo64;
34
35 static uint32_t
36 elf_32_to_file (uint32_t x, int file_is_little_endian)
37 {
38   volatile uint32_t out;
39   unsigned char *outbytes;
40
41   outbytes = (unsigned char *)&out;
42   if (file_is_little_endian)
43     {
44       outbytes[0] = (x >> 0) & 0xff;
45       outbytes[1] = (x >> 8) & 0xff;
46       outbytes[2] = (x >> 16) & 0xff;
47       outbytes[3] = (x >> 24) & 0xff;
48     }
49   else /* big endian */
50     {
51       outbytes[0] = (x >> 24) & 0xff;
52       outbytes[1] = (x >> 16) & 0xff;
53       outbytes[2] = (x >> 8) & 0xff;
54       outbytes[3] = (x >> 0) & 0xff;
55     }
56   
57   return out;
58 }
59
60 static uint64_t
61 elf_64_to_file (uint64_t x, int file_is_little_endian)
62 {
63   volatile uint64_t out;
64   unsigned char *outbytes;
65   int i;
66
67   outbytes = (unsigned char *)&out;
68   if (file_is_little_endian)
69     {
70       for (i = 0; i < 8; i++)
71         outbytes[i] = (x >> (8*i)) & 0xff;
72     }
73   else /* big endian */
74     {
75       for (i = 0; i < 8; i++)
76         outbytes[7-i] = (x >> (8*i)) & 0xff;
77     }
78   
79   return out;
80 }
81
82 static Elf32_Word
83 word32_to_file (Elf32_Word x, Elf *elf)
84 {
85   Elf32_Ehdr *ehdr = elf32_getehdr (elf);
86   return elf_32_to_file (x, ehdr->e_ident[EI_DATA] & ELFDATA2LSB);
87 }
88
89 static Elf32_Off
90 off32_to_file (Elf32_Off x, Elf *elf)
91 {
92   Elf32_Ehdr *ehdr = elf32_getehdr (elf);
93   return elf_32_to_file (x, ehdr->e_ident[EI_DATA] & ELFDATA2LSB);
94 }
95
96 static Elf64_Word
97 word64_to_file (Elf64_Word x, Elf *elf)
98 {
99   Elf64_Ehdr *ehdr = elf64_getehdr (elf);
100   return elf_32_to_file (x, ehdr->e_ident[EI_DATA] & ELFDATA2LSB);
101 }
102
103 static Elf64_Off
104 off64_to_file (Elf64_Off x, Elf *elf)
105 {
106   Elf64_Ehdr *ehdr = elf64_getehdr (elf);
107   return elf_64_to_file (x, ehdr->e_ident[EI_DATA] & ELFDATA2LSB);
108 }
109
110 static uint32_t
111 elf_32_from_file (uint32_t x, int file_is_little_endian)
112 {
113   unsigned char *inbytes;
114
115   inbytes = (unsigned char *)&x;
116   if (file_is_little_endian)
117     {
118       return 
119         (inbytes[0] << 0) |
120         (inbytes[1] << 8) |
121         (inbytes[2] << 16) |
122         (inbytes[3] << 24);
123     }
124   else /* big endian */
125     {
126       return 
127         (inbytes[0] << 24) |
128         (inbytes[1] << 16) |
129         (inbytes[2] << 8) |
130         (inbytes[3] << 0);
131     }
132 }
133
134 static uint64_t
135 elf_64_from_file (uint64_t x, int file_is_little_endian)
136 {
137   unsigned char *inbytes;
138
139   inbytes = (unsigned char *)&x;
140   if (file_is_little_endian)
141     {
142       return 
143         ((uint64_t)inbytes[0] << 0) |
144         ((uint64_t)inbytes[1] << 8) |
145         ((uint64_t)inbytes[2] << 16) |
146         ((uint64_t)inbytes[3] << 24) |
147         ((uint64_t)inbytes[4] << 32) |
148         ((uint64_t)inbytes[5] << 40) |
149         ((uint64_t)inbytes[6] << 48) |
150         ((uint64_t)inbytes[7] << 56);
151     }
152   else /* big endian */
153     {
154       return 
155         ((uint64_t)inbytes[0] << 56) |
156         ((uint64_t)inbytes[1] << 48) |
157         ((uint64_t)inbytes[2] << 40) |
158         ((uint64_t)inbytes[3] << 32) |
159         ((uint64_t)inbytes[4] << 24) |
160         ((uint64_t)inbytes[5] << 16) |
161         ((uint64_t)inbytes[6] << 8) |
162         ((uint64_t)inbytes[7] << 0);
163     }
164 }
165
166 static Elf32_Word
167 word32_from_file (Elf32_Word x, Elf *elf)
168 {
169   Elf32_Ehdr *ehdr = elf32_getehdr (elf);
170   return elf_32_from_file (x, ehdr->e_ident[EI_DATA] & ELFDATA2LSB);
171 }
172
173 static Elf32_Off
174 off32_from_file (Elf32_Off x, Elf *elf)
175 {
176   Elf32_Ehdr *ehdr = elf32_getehdr (elf);
177   return elf_32_from_file (x, ehdr->e_ident[EI_DATA] & ELFDATA2LSB);
178 }
179
180 static Elf64_Word
181 word64_from_file (Elf64_Word x, Elf *elf)
182 {
183   Elf64_Ehdr *ehdr = elf64_getehdr (elf);
184   return elf_32_from_file (x, ehdr->e_ident[EI_DATA] & ELFDATA2LSB);
185 }
186
187 static Elf64_Off
188 off64_from_file (Elf64_Off x, Elf *elf)
189 {
190   Elf64_Ehdr *ehdr = elf64_getehdr (elf);
191   return elf_64_from_file (x, ehdr->e_ident[EI_DATA] & ELFDATA2LSB);
192 }
193
194 static void
195 unstrip_info_to_data32 (UnstripInfo *info,
196                         Elf *elf,
197                         Elf_Data *data)
198 {
199   UnstripInfo32 *info32;
200   int i;
201   
202   data->d_align = 4;
203
204   data->d_size =
205     /* orig_e_shoff */ sizeof (Elf32_Off) +
206     /* n_sections */ sizeof (Elf32_Off) +
207     /* sections */ info->n_sections * sizeof (UnstripInfoSection32);
208
209   data->d_buf = calloc (1, data->d_size);
210
211   info32 = (UnstripInfo32 *) data->d_buf;
212
213   info32->orig_e_shoff = off32_to_file (info->orig_e_shoff, elf);
214   info32->n_sections = off32_to_file (info->n_sections, elf);
215
216   for (i = 0; i < info->n_sections; i++)
217     {
218       info32->sections[i].debug_section = word32_to_file (info->sections[i].debug_section, elf);
219       info32->sections[i].name = word32_to_file (info->sections[i].name, elf);
220       info32->sections[i].orig_offset = off32_to_file (info->sections[i].orig_offset, elf);
221     }
222 }
223
224 static void
225 unstrip_info_to_data64 (UnstripInfo *info,
226                         Elf *elf,
227                         Elf_Data *data)
228 {
229   UnstripInfo64 *info64;
230   int i;
231   
232   data->d_align = 8;
233   
234   data->d_size =
235     /* orig_e_shoff */ sizeof (Elf64_Off) +
236     /* n_sections */ sizeof (Elf64_Off) +
237     /* sections */ info->n_sections * sizeof (UnstripInfoSection64);
238
239   data->d_buf = calloc (1, data->d_size);
240
241   info64 = (UnstripInfo64 *) data->d_buf;
242
243   info64->orig_e_shoff = off64_to_file (info->orig_e_shoff, elf);
244   info64->n_sections = off64_to_file (info->n_sections, elf);
245
246   for (i = 0; i < info->n_sections; i++)
247     {
248       info64->sections[i].debug_section = word64_to_file (info->sections[i].debug_section, elf);
249       info64->sections[i].name = word64_to_file (info->sections[i].name, elf);
250       info64->sections[i].orig_offset = off64_to_file (info->sections[i].orig_offset, elf);
251     }
252 }
253
254 void
255 unstrip_info_to_data (UnstripInfo *info,
256                       Elf *elf,
257                       Elf_Data *data)
258 {
259   GElf_Ehdr ehdr;
260   
261   data->d_type = ELF_T_BYTE;
262   data->d_off = 0;
263
264   gelf_getehdr (elf, &ehdr);
265   if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
266     unstrip_info_to_data32 (info, elf, data);
267   else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
268     unstrip_info_to_data64 (info, elf, data);
269   else
270     fprintf (stderr, "Warning. unsupported elf class\n");
271 }
272
273 static void
274 unstrip_info_from_data32 (UnstripInfo *info,
275                           Elf *elf,
276                           Elf_Data *data)
277 {
278   UnstripInfo32 *info32;
279   int i;
280   
281   info32 = (UnstripInfo32 *) data->d_buf;
282   
283   info->orig_e_shoff = off32_from_file (info32->orig_e_shoff, elf);
284   info->n_sections = off32_from_file (info32->n_sections, elf);
285
286   info->sections = calloc (info->n_sections, sizeof (UnstripInfoSection));
287   for (i = 0; i < info->n_sections; i++)
288     {
289       info->sections[i].debug_section = word32_from_file (info32->sections[i].debug_section, elf);
290       info->sections[i].name = word32_from_file (info32->sections[i].name, elf);
291       info->sections[i].orig_offset = off32_from_file (info32->sections[i].orig_offset, elf);
292     }
293 }
294
295 static void
296 unstrip_info_from_data64 (UnstripInfo *info,
297                           Elf *elf,
298                           Elf_Data *data)
299 {
300   UnstripInfo64 *info64;
301   int i;
302   
303   info64 = (UnstripInfo64 *) data->d_buf;
304   
305   info->orig_e_shoff = off64_from_file (info64->orig_e_shoff, elf);
306   info->n_sections = off64_from_file (info64->n_sections, elf);
307
308   info->sections = calloc (info->n_sections, sizeof (UnstripInfoSection));
309   for (i = 0; i < info->n_sections; i++)
310     {
311       info->sections[i].debug_section = word64_from_file (info64->sections[i].debug_section, elf);
312       info->sections[i].name = word64_from_file (info64->sections[i].name, elf);
313       info->sections[i].orig_offset = off64_from_file (info64->sections[i].orig_offset, elf);
314     }
315 }
316
317 UnstripInfo *
318 unstrip_info_from_data (Elf *elf,
319                         Elf_Data *data)
320 {
321   GElf_Ehdr ehdr;
322   
323   UnstripInfo *info;
324
325   info = malloc (sizeof (UnstripInfo));
326
327   gelf_getehdr (elf, &ehdr);
328   if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
329     unstrip_info_from_data32 (info, elf, data);
330   else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
331     unstrip_info_from_data64 (info, elf, data);
332   else
333     fprintf (stderr, "Warning. unsupported elf class\n");
334   
335   return info;
336 }
337
338 static void
339 debug_link_to_data32 (DebugLink *debuglink,
340                       Elf *elf,
341                       Elf_Data *data)
342 {
343   size_t namelen_aligned;
344   char *p;
345   
346   data->d_align = 4;
347
348   namelen_aligned = align_up (strlen(debuglink->filename) + 1, 4);
349
350   data->d_size =
351     /* name */ namelen_aligned +
352     /* checksum */ sizeof (Elf32_Word);
353
354   data->d_buf = calloc (1, data->d_size);
355
356   strcpy (data->d_buf, debuglink->filename);
357   p = ((char *)data->d_buf) + namelen_aligned;
358   
359   *(Elf32_Word *)p = word32_to_file (debuglink->checksum, elf);
360 }
361
362 static void
363 debug_link_to_data64 (DebugLink *debuglink,
364                       Elf *elf,
365                       Elf_Data *data)
366 {
367   size_t namelen_aligned;
368   char *p;
369   
370   data->d_align = 4;
371
372   namelen_aligned = align_up (strlen(debuglink->filename) + 1, 4);
373
374   data->d_size =
375     /* name */ namelen_aligned +
376     /* checksum */ sizeof (Elf64_Word);
377
378   data->d_buf = calloc (1, data->d_size);
379
380   strcpy (data->d_buf, debuglink->filename);
381   p = ((char *)data->d_buf) + namelen_aligned;
382   
383   *(Elf64_Word *)p = word64_to_file (debuglink->checksum, elf);
384 }
385
386 void
387 debug_link_to_data (DebugLink *debuglink, Elf *elf, Elf_Data *data)
388 {
389   GElf_Ehdr ehdr;
390   
391   data->d_type = ELF_T_BYTE;
392   data->d_off = 0;
393
394   gelf_getehdr (elf, &ehdr);
395   if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
396     debug_link_to_data32 (debuglink, elf, data);
397   else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
398     debug_link_to_data64 (debuglink, elf, data);
399   else
400     fprintf (stderr, "Warning. unsupported elf class\n");
401 }
402
403 static void
404 debug_link_from_data32 (DebugLink *debuglink,
405                         Elf *elf,
406                         Elf_Data *data)
407 {
408   size_t namelen_aligned;
409   char *p;
410   
411   debuglink->filename = strdup (data->d_buf);
412
413   namelen_aligned = align_up (strlen (debuglink->filename) + 1, 4);
414
415   p = ((char *)data->d_buf) + namelen_aligned;
416   
417   debuglink->checksum = word32_from_file (*(Elf32_Word *)p, elf);
418 }
419
420 static void
421 debug_link_from_data64 (DebugLink *debuglink,
422                         Elf *elf,
423                         Elf_Data *data)
424 {
425   size_t namelen_aligned;
426   char *p;
427   
428   debuglink->filename = strdup (data->d_buf);
429
430   namelen_aligned = align_up (strlen (debuglink->filename) + 1, 4);
431
432   p = ((char *)data->d_buf) + namelen_aligned;
433   
434   debuglink->checksum = word64_from_file (*(Elf64_Word *)p, elf);
435 }
436
437
438 DebugLink *
439 debug_link_from_data (Elf *elf, Elf_Data *data)
440 {
441   GElf_Ehdr ehdr;
442   DebugLink *debuglink;
443
444   debuglink = malloc (sizeof (DebugLink));
445
446   gelf_getehdr (elf, &ehdr);
447   if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
448     debug_link_from_data32 (debuglink, elf, data);
449   else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
450     debug_link_from_data64 (debuglink, elf, data);
451   else
452     fprintf (stderr, "Warning. unsupported elf class\n");
453   
454   return debuglink;
455 }
456