1 /* Needed for libelf */
2 #define _FILE_OFFSET_BITS 64
16 char *output_dir = NULL;
18 int keep_all_section_headers = 1;
19 int add_unstrip_info = 0;
23 copy_to_file(Elf *elf, Elf *out_elf)
27 Elf_Scn *section, *out_section;
28 GElf_Shdr section_header;
29 Elf_Data *data, *out_data;
32 elf_flagelf (out_elf, ELF_C_SET, ELF_F_LAYOUT);
34 gelf_getehdr (elf, &ehdr);
36 /* copy elf header: */
37 gelf_newehdr(out_elf, ehdr.e_ident[EI_CLASS]);
39 gelf_update_ehdr (out_elf, &ehdr);
42 while ((section = elf_nextscn(elf, section)) != NULL)
44 out_section = elf_newscn(out_elf);
46 /* Copy section header */
47 gelf_getshdr (section, §ion_header);
48 gelf_update_shdr(out_section, §ion_header);
53 while ((data = elf_rawdata (section, data)))
55 out_data = elf_newdata (out_section);
57 out_data->d_buf = data->d_buf;
58 out_data->d_type = data->d_type;
59 out_data->d_size = data->d_size;
60 out_data->d_off = data->d_off;
61 out_data->d_align = section_header.sh_addralign;
62 out_data->d_version = data->d_version;
69 strip_to_file(Elf *elf, Elf *out_elf, DebugLink *debuglink)
74 Elf_Scn *section, *out_section;
75 GElf_Shdr section_header;
76 Elf_Data *data, *out_data;
77 unsigned char *section_strtab;
83 int debuglink_name = 0;
85 elf_flagelf (out_elf, ELF_C_SET, ELF_F_LAYOUT);
87 gelf_getehdr (elf, &ehdr);
89 /* copy elf header: */
90 gelf_newehdr(out_elf, ehdr.e_ident[EI_CLASS]);
91 gelf_update_ehdr(out_elf, &ehdr);
93 section_map = calloc(ehdr.e_shnum, sizeof (size_t));
95 /* Locate section header strtab */
96 section = elf_getscn(elf, ehdr.e_shstrndx);
97 data = elf_getdata(section, NULL);
98 section_strtab = data->d_buf;
100 /* Copy program headers: */
101 gelf_newphdr(out_elf, ehdr.e_phnum);
103 for (i = 0; i < ehdr.e_phnum; i++)
105 gelf_getphdr (elf, i, &phdr);
106 gelf_update_phdr (out_elf, i, &phdr);
109 /* Copy section headers */
113 while ((section = elf_nextscn(elf, section)) != NULL)
117 gelf_getshdr (section, §ion_header);
119 section_name = section_strtab + section_header.sh_name;
122 !string_has_prefix (section_name, ".stab") &&
123 !string_has_prefix (section_name, ".debug") &&
126 !string_has_prefix (section_name, ".symtab") &&
127 !string_has_prefix (section_name, ".strtab")));
131 out_section = elf_newscn(out_elf);
133 section_map[elf_ndxscn(section)] = elf_ndxscn(out_section);
135 /* Update offset if necessary */
137 section_header.sh_offset = align_up (last_offset, section_header.sh_addralign);
142 while ((data = elf_rawdata (section, data)))
144 out_data = elf_newdata(out_section);
146 /* Add ".debuglink" to section header strtab */
147 if (ehdr.e_shstrndx == elf_ndxscn(section))
149 out_data->d_size = data->d_size + strlen (DEBUGLINKNAME) + 1;
150 out_data->d_buf = malloc (out_data->d_size);
151 memcpy (out_data->d_buf, data->d_buf, data->d_size);
152 strcpy (out_data->d_buf + data->d_size, DEBUGLINKNAME);
154 section_header.sh_size = MAX (section_header.sh_size, out_data->d_off + out_data->d_size);
156 debuglink_name = data->d_size;
160 out_data->d_buf = data->d_buf;
161 out_data->d_size = data->d_size;
163 out_data->d_off = data->d_off;
164 out_data->d_type = data->d_type;
165 out_data->d_align = section_header.sh_addralign;
166 out_data->d_version = data->d_version;
169 last_offset = section_header.sh_offset + section_header.sh_size;
170 /* Write section header */
171 gelf_update_shdr(out_section, §ion_header);
178 /* Add debuglink section header */
179 out_section = elf_newscn(out_elf);
180 section_header.sh_name = debuglink_name;
181 section_header.sh_type = SHT_PROGBITS;
182 section_header.sh_flags = 0;
183 section_header.sh_addr = 0;
184 section_header.sh_addralign = 4;
185 section_header.sh_offset = align_up (last_offset, section_header.sh_addralign);
186 section_header.sh_size = 0;
187 section_header.sh_link = 0;
188 section_header.sh_info = 0;
189 section_header.sh_entsize = 0;
191 out_data = elf_newdata(out_section);
192 debug_link_to_data (debuglink, elf, out_data);
194 section_header.sh_size = out_data->d_size;
196 last_offset = section_header.sh_offset + section_header.sh_size;
197 gelf_update_shdr(out_section, §ion_header);
199 /* Update section header stringtab ref */
200 gelf_getehdr (out_elf, &out_ehdr);
201 out_ehdr.e_shstrndx = section_map[out_ehdr.e_shstrndx];
202 out_ehdr.e_shoff = align_up (last_offset, 8);
203 gelf_update_ehdr(out_elf, &out_ehdr);
205 /* Update section header links */
207 while ((out_section = elf_nextscn(out_elf, out_section)) != NULL)
209 gelf_getshdr (out_section, §ion_header);
211 section_header.sh_link = section_map[section_header.sh_link];
213 if (section_header.sh_type == SHT_REL ||
214 section_header.sh_type == SHT_RELA)
215 section_header.sh_info = section_map[section_header.sh_info];
217 gelf_update_shdr(out_section, §ion_header);
222 copy_debuginfo_to_file(Elf *elf, Elf *out_elf)
225 Elf_Scn *section, *out_section;
226 GElf_Shdr section_header;
227 GElf_Shdr out_section_header;
228 Elf_Data *data, *out_data;
230 unsigned char *section_strtab;
233 int unstripinfo_name = 0;
236 info = malloc (sizeof (UnstripInfo));
238 if (gelf_getehdr (elf, &ehdr) == NULL)
240 fprintf (stderr, "Not an elf binary, exiting\n");
244 gelf_newehdr(out_elf, ehdr.e_ident[EI_CLASS]);
246 /* copy elf header: */
247 gelf_update_ehdr(out_elf, &ehdr);
249 info->orig_e_shoff = ehdr.e_shoff;
250 info->n_sections = ehdr.e_shnum;
251 info->sections = calloc (info->n_sections, sizeof (UnstripInfoSection));
253 /* Locate section header strtab */
254 section = elf_getscn(elf, ehdr.e_shstrndx);
255 data = elf_getdata(section, NULL);
256 section_strtab = data->d_buf;
258 /* Copy section headers */
260 while ((section = elf_nextscn(elf, section)) != NULL)
263 size_t section_index;
264 GElf_Off last_offset;
265 gelf_getshdr (section, §ion_header);
267 section_index = elf_ndxscn(section);
268 info->sections[section_index].name = section_header.sh_name;
269 info->sections[section_index].orig_offset = section_header.sh_offset;
270 info->sections[section_index].debug_section = 0;
272 section_name = section_strtab + section_header.sh_name;
275 string_has_prefix (section_name, ".stab") ||
276 string_has_prefix (section_name, ".debug") ||
277 string_has_prefix (section_name, ".symtab") ||
278 string_has_prefix (section_name, ".strtab") ||
279 section_index == ehdr.e_shstrndx;
283 out_section = elf_newscn(out_elf);
285 info->sections[section_index].debug_section = elf_ndxscn(out_section);
287 memset (&out_section_header, 0, sizeof(out_section_header));
288 out_section_header.sh_name = section_header.sh_name;
289 out_section_header.sh_type = section_header.sh_type;
290 out_section_header.sh_flags = section_header.sh_flags;
291 out_section_header.sh_addr = section_header.sh_addr;
292 out_section_header.sh_offset = section_header.sh_offset;
293 out_section_header.sh_size = section_header.sh_size;
294 out_section_header.sh_link = section_header.sh_link;
295 out_section_header.sh_info = section_header.sh_info;
296 out_section_header.sh_addralign = section_header.sh_addralign;
297 out_section_header.sh_entsize = section_header.sh_entsize;
298 gelf_update_shdr(out_section, &out_section_header);
304 while ((data = elf_rawdata (section, data)))
306 out_data = elf_newdata(out_section);
308 if (ehdr.e_shstrndx == elf_ndxscn(section))
310 out_data->d_size = data->d_size + strlen (UNSTRIPINFONAME) + 1;
311 out_data->d_buf = malloc (out_data->d_size);
312 memcpy (out_data->d_buf, data->d_buf, data->d_size);
313 strcpy (out_data->d_buf + data->d_size, UNSTRIPINFONAME);
315 unstripinfo_name = data->d_size;
319 out_data->d_buf = data->d_buf;
320 out_data->d_size = data->d_size;
322 out_data->d_off = data->d_off;
323 out_data->d_type = data->d_type;
324 out_data->d_align = section_header.sh_addralign;
325 out_data->d_version = data->d_version;
329 else if (keep_all_section_headers)
331 out_section = elf_newscn(out_elf);
333 info->sections[section_index].debug_section = 0;
335 section_header.sh_type = SHT_NOBITS;
336 gelf_update_shdr(out_section, §ion_header);
338 if ((data = elf_rawdata (section, data)))
340 out_data = elf_newdata(out_section);
342 out_data->d_buf = NULL;
343 out_data->d_size = data->d_size;
344 out_data->d_off = data->d_off;
345 out_data->d_type = data->d_type;
346 out_data->d_align = section_header.sh_addralign;
347 out_data->d_version = data->d_version;
353 /* Add unlinkinfo section header */
354 if (add_unstrip_info)
356 out_section = elf_newscn(out_elf);
357 section_header.sh_name = unstripinfo_name;
358 section_header.sh_type = SHT_PROGBITS;
359 section_header.sh_flags = 0;
360 section_header.sh_addr = 0;
361 section_header.sh_addralign = 4;
362 section_header.sh_link = 0;
363 section_header.sh_info = 0;
364 section_header.sh_entsize = 0;
366 out_data = elf_newdata(out_section);
367 unstrip_info_to_data (info, elf, out_data);
369 gelf_update_shdr(out_section, §ion_header);
372 /* Update section header stringtab ref */
373 gelf_getehdr (out_elf, &ehdr);
374 ehdr.e_shstrndx = info->sections[ehdr.e_shstrndx].debug_section;
375 gelf_update_ehdr(out_elf, &ehdr);
377 /* Update section header links */
379 while ((out_section = elf_nextscn(out_elf, out_section)) != NULL)
381 gelf_getshdr (out_section, &out_section_header);
382 out_section_header.sh_link = info->sections[out_section_header.sh_link].debug_section;
383 gelf_update_shdr(out_section, &out_section_header);
388 static struct poptOption optionsTable[] = {
389 { "output-dir", 'o', POPT_ARG_STRING, &output_dir, 0,
390 "directory to store result", "/usr/lib/debug" },
391 { "strip-debug", 'g', POPT_ARG_NONE, &keep_strtab, 0,
392 "Remove debugging symbols only, keep symbols", 0 },
393 { "unstrip-info", 'u', POPT_ARG_NONE, &add_unstrip_info, 0,
394 "Add unstripping information to the debug file", 0 },
396 { NULL, 0, 0, NULL, 0 }
400 main (int argc, char *argv[])
404 const char *origname;
406 char *debugname, *strippedname;
407 DebugLink *debuglink;
408 poptContext optCon; /* context for parsing command-line options */
411 struct stat stat_buf;
413 optCon = poptGetContext("striptofile", argc, (const char **)argv,
416 while ((nextopt = poptGetNextOpt (optCon)) > 0 || nextopt == POPT_ERROR_BADOPT)
421 fprintf (stderr, "Error on option %s: %s.\nRun '%s --help' to see a full list of available command line options.\n",
422 poptBadOption (optCon, 0),
423 poptStrerror (nextopt),
428 args = poptGetArgs (optCon);
429 if (args == NULL || args[0] == NULL || args[1] != NULL)
431 poptPrintHelp(optCon, stdout, 0);
439 origname_base = path_basename (origname);
440 debugname = strconcat (output_dir, "/", origname_base, ".debug", NULL);
441 free (origname_base);
444 debugname = strconcat (origname, ".debug", NULL);
446 strippedname = strconcat (origname, ".XXXXXX", NULL);
448 if (elf_version(EV_CURRENT) == EV_NONE)
450 fprintf (stderr, "library out of date\n");
454 fd = open (origname, O_RDONLY);
457 fprintf (stderr, "Failed to open input file: %s\n", origname);
461 elf = elf_begin (fd, ELF_C_READ, NULL);
464 fprintf (stderr, "Failed to elf_begin input file: %s\n", origname);
468 /* Create debug file: */
469 out = open (debugname, O_RDWR | O_TRUNC | O_CREAT, 0644);
472 fprintf (stderr, "Failed to open output file: %s\n", debugname);
476 out_elf = elf_begin (out, ELF_C_WRITE_MMAP, NULL);
479 fprintf (stderr, "Failed to elf_begin output file: %s\n", debugname);
483 copy_debuginfo_to_file (elf, out_elf);
485 if (elf_update (out_elf, ELF_C_WRITE) < 0)
487 fprintf (stderr, "Failed to write debug file: %s\n", elf_errmsg (elf_errno()));
493 debuglink = malloc (sizeof (DebugLink));
494 debuglink->filename = path_basename (debugname);
495 debuglink->checksum = crc32_file (debugname);
497 /* Create stripped file: */
498 out = mkstemp (strippedname);
501 fprintf (stderr, "Failed to open output file: %s\n", strippedname);
505 /* Copy access rights */
506 if (fstat(fd, &stat_buf) == 0)
507 fchmod(out, stat_buf.st_mode);
509 out_elf = elf_begin (out, ELF_C_WRITE, NULL);
512 fprintf (stderr, "Failed to elf_begin output file: %s\n", strippedname);
516 strip_to_file (elf, out_elf, debuglink);
518 if (elf_update (out_elf, ELF_C_WRITE) < 0)
520 fprintf (stderr, "Failed to write stripped file: %s\n", elf_errmsg (elf_errno()));
530 if (rename (strippedname, origname) != 0)
531 fprintf(stderr, "unable to write to %s\n", origname);
533 unlink (strippedname);
535 poptFreeContext (optCon);