13 char *output_dir = NULL;
15 int keep_all_section_headers = 1;
16 int add_unstrip_info = 0;
20 copy_to_file(Elf *elf, Elf *out_elf)
24 Elf_Scn *section, *out_section;
25 GElf_Shdr section_header;
26 Elf_Data *data, *out_data;
29 elf_flagelf (out_elf, ELF_C_SET, ELF_F_LAYOUT);
31 gelf_getehdr (elf, &ehdr);
33 /* copy elf header: */
34 gelf_newehdr(out_elf, ehdr.e_ident[EI_CLASS]);
35 gelf_update_ehdr(out_elf, &ehdr);
37 /* Copy program headers: */
38 gelf_newphdr(out_elf, ehdr.e_phnum);
40 for (i = 0; i < ehdr.e_phnum; i++)
42 gelf_getphdr (elf, i, &phdr);
43 gelf_update_phdr(out_elf, i, &phdr);
47 while ((section = elf_nextscn(elf, section)) != NULL)
49 out_section = elf_newscn(out_elf);
51 /* Copy section header */
52 gelf_getshdr (section, §ion_header);
53 gelf_update_shdr(out_section, §ion_header);
58 while ((data = elf_rawdata (section, data)))
60 out_data = elf_newdata (out_section);
62 out_data->d_buf = data->d_buf;
63 out_data->d_type = data->d_type;
64 out_data->d_size = data->d_size;
65 out_data->d_off = data->d_off;
66 out_data->d_align = section_header.sh_addralign;
67 out_data->d_version = data->d_version;
74 strip_to_file(Elf *elf, Elf *out_elf, DebugLink *debuglink)
79 Elf_Scn *section, *out_section;
80 GElf_Shdr section_header;
81 Elf_Data *data, *out_data;
82 unsigned char *section_strtab;
88 int debuglink_name = 0;
90 elf_flagelf (out_elf, ELF_C_SET, ELF_F_LAYOUT);
92 gelf_getehdr (elf, &ehdr);
94 /* copy elf header: */
95 gelf_newehdr(out_elf, ehdr.e_ident[EI_CLASS]);
96 gelf_update_ehdr(out_elf, &ehdr);
98 section_map = calloc(ehdr.e_shnum, sizeof (size_t));
100 /* Locate section header strtab */
101 section = elf_getscn(elf, ehdr.e_shstrndx);
102 data = elf_getdata(section, NULL);
103 section_strtab = data->d_buf;
105 /* Copy program headers: */
106 gelf_newphdr(out_elf, ehdr.e_phnum);
108 for (i = 0; i < ehdr.e_phnum; i++)
110 gelf_getphdr (elf, i, &phdr);
111 gelf_update_phdr(out_elf, i, &phdr);
114 /* Copy section headers */
118 while ((section = elf_nextscn(elf, section)) != NULL)
122 gelf_getshdr (section, §ion_header);
124 section_name = section_strtab + section_header.sh_name;
127 !string_has_prefix (section_name, ".stab") &&
128 !string_has_prefix (section_name, ".debug") &&
131 !string_has_prefix (section_name, ".symtab") &&
132 !string_has_prefix (section_name, ".strtab")));
136 out_section = elf_newscn(out_elf);
138 section_map[elf_ndxscn(section)] = elf_ndxscn(out_section);
140 /* Update offset if necessary */
142 section_header.sh_offset = align_up (last_offset, section_header.sh_addralign);
147 while ((data = elf_rawdata (section, data)))
149 out_data = elf_newdata(out_section);
151 /* Add ".debuglink" to section header strtab */
152 if (ehdr.e_shstrndx == elf_ndxscn(section))
154 out_data->d_size = data->d_size + strlen (DEBUGLINKNAME) + 1;
155 out_data->d_buf = malloc (out_data->d_size);
156 memcpy (out_data->d_buf, data->d_buf, data->d_size);
157 strcpy (out_data->d_buf + data->d_size, DEBUGLINKNAME);
159 section_header.sh_size += out_data->d_size;
161 debuglink_name = data->d_size;
165 out_data->d_buf = data->d_buf;
166 out_data->d_size = data->d_size;
168 out_data->d_off = data->d_off;
169 out_data->d_type = data->d_type;
170 out_data->d_align = section_header.sh_addralign;
171 out_data->d_version = data->d_version;
174 last_offset = section_header.sh_offset + section_header.sh_size;
175 /* Write section header */
176 gelf_update_shdr(out_section, §ion_header);
183 /* Add debuglink section header */
184 out_section = elf_newscn(out_elf);
185 section_header.sh_name = debuglink_name;
186 section_header.sh_type = SHT_PROGBITS;
187 section_header.sh_flags = 0;
188 section_header.sh_addr = 0;
189 section_header.sh_addralign = 4;
190 section_header.sh_offset = align_up (last_offset, section_header.sh_addralign);
191 section_header.sh_size = 0;
192 section_header.sh_link = 0;
193 section_header.sh_info = 0;
194 section_header.sh_entsize = 0;
196 out_data = elf_newdata(out_section);
197 debug_link_to_data (debuglink, elf, out_data);
199 section_header.sh_size = out_data->d_size;
201 last_offset = section_header.sh_offset + section_header.sh_size;
202 gelf_update_shdr(out_section, §ion_header);
204 /* Update section header stringtab ref */
205 gelf_getehdr (out_elf, &out_ehdr);
206 out_ehdr.e_shstrndx = section_map[out_ehdr.e_shstrndx];
207 out_ehdr.e_shoff = align_up (last_offset, 8);
208 gelf_update_ehdr(out_elf, &out_ehdr);
210 /* Update section header links */
212 while ((out_section = elf_nextscn(out_elf, out_section)) != NULL)
214 gelf_getshdr (out_section, §ion_header);
216 section_header.sh_link = section_map[section_header.sh_link];
218 if (section_header.sh_type == SHT_REL ||
219 section_header.sh_type == SHT_RELA)
220 section_header.sh_info = section_map[section_header.sh_info];
222 gelf_update_shdr(out_section, §ion_header);
227 copy_debuginfo_to_file(Elf *elf, Elf *out_elf)
230 Elf_Scn *section, *out_section;
231 GElf_Shdr section_header;
232 GElf_Shdr out_section_header;
233 Elf_Data *data, *out_data;
234 unsigned char *section_strtab;
237 int unstripinfo_name = 0;
239 info = malloc (sizeof (UnstripInfo));
241 if (gelf_getehdr (elf, &ehdr) == NULL)
243 fprintf (stderr, "Not an elf binary, exiting\n");
247 gelf_newehdr(out_elf, ehdr.e_ident[EI_CLASS]);
249 /* copy elf header: */
250 gelf_update_ehdr(out_elf, &ehdr);
252 info->orig_e_shoff = ehdr.e_shoff;
253 info->n_sections = ehdr.e_shnum;
254 info->sections = calloc (info->n_sections, sizeof (UnstripInfoSection));
256 /* Locate section header strtab */
257 section = elf_getscn(elf, ehdr.e_shstrndx);
258 data = elf_getdata(section, NULL);
259 section_strtab = data->d_buf;
261 /* Copy section headers */
263 while ((section = elf_nextscn(elf, section)) != NULL)
266 size_t section_index;
267 GElf_Off last_offset;
268 gelf_getshdr (section, §ion_header);
270 section_index = elf_ndxscn(section);
271 info->sections[section_index].name = section_header.sh_name;
272 info->sections[section_index].orig_offset = section_header.sh_offset;
273 info->sections[section_index].debug_section = 0;
275 section_name = section_strtab + section_header.sh_name;
278 string_has_prefix (section_name, ".stab") ||
279 string_has_prefix (section_name, ".debug") ||
280 string_has_prefix (section_name, ".symtab") ||
281 string_has_prefix (section_name, ".strtab") ||
282 section_index == ehdr.e_shstrndx;
286 out_section = elf_newscn(out_elf);
288 info->sections[section_index].debug_section = elf_ndxscn(out_section);
290 memset (&out_section_header, 0, sizeof(out_section_header));
291 out_section_header.sh_name = section_header.sh_name;
292 out_section_header.sh_type = section_header.sh_type;
293 out_section_header.sh_flags = section_header.sh_flags;
294 out_section_header.sh_addr = section_header.sh_addr;
295 out_section_header.sh_offset = section_header.sh_offset;
296 out_section_header.sh_size = section_header.sh_size;
297 out_section_header.sh_link = section_header.sh_link;
298 out_section_header.sh_info = section_header.sh_info;
299 out_section_header.sh_addralign = section_header.sh_addralign;
300 out_section_header.sh_entsize = section_header.sh_entsize;
301 gelf_update_shdr(out_section, &out_section_header);
307 while ((data = elf_rawdata (section, data)))
309 out_data = elf_newdata(out_section);
311 out_data->d_buf = data->d_buf;
312 out_data->d_type = data->d_type;
313 out_data->d_size = data->d_size;
314 out_data->d_off = data->d_off;
315 out_data->d_align = section_header.sh_addralign;
316 out_data->d_version = data->d_version;
317 last_offset = out_data->d_off + out_data->d_size;
319 /* Add ".debuglink" to section header strtab */
320 if (ehdr.e_shstrndx == elf_ndxscn(section))
322 out_data = elf_newdata(out_section);
324 out_data->d_size = strlen (UNSTRIPINFONAME) + 1;
325 out_data->d_buf = UNSTRIPINFONAME;
326 out_data->d_off = last_offset;
327 out_data->d_align = 0;
329 unstripinfo_name = out_data->d_off;
332 else if (keep_all_section_headers)
334 out_section = elf_newscn(out_elf);
336 info->sections[section_index].debug_section = 0;
338 section_header.sh_type = SHT_NOBITS;
339 gelf_update_shdr(out_section, §ion_header);
341 if ((data = elf_rawdata (section, data)))
343 out_data = elf_newdata(out_section);
345 out_data->d_buf = NULL;
346 out_data->d_size = data->d_size;
347 out_data->d_off = data->d_off;
348 out_data->d_type = data->d_type;
349 out_data->d_align = section_header.sh_addralign;
350 out_data->d_version = data->d_version;
356 /* Add unlinkinfo section header */
357 if (add_unstrip_info)
359 out_section = elf_newscn(out_elf);
360 section_header.sh_name = unstripinfo_name;
361 section_header.sh_type = SHT_PROGBITS;
362 section_header.sh_flags = 0;
363 section_header.sh_addr = 0;
364 section_header.sh_addralign = 4;
365 section_header.sh_link = 0;
366 section_header.sh_info = 0;
367 section_header.sh_entsize = 0;
369 out_data = elf_newdata(out_section);
370 unstrip_info_to_data (info, elf, out_data);
372 gelf_update_shdr(out_section, §ion_header);
375 /* Update section header stringtab ref */
376 gelf_getehdr (out_elf, &ehdr);
377 ehdr.e_shstrndx = info->sections[ehdr.e_shstrndx].debug_section;
378 gelf_update_ehdr(out_elf, &ehdr);
380 /* Update section header links */
382 while ((out_section = elf_nextscn(out_elf, out_section)) != NULL)
384 gelf_getshdr (out_section, &out_section_header);
385 out_section_header.sh_link = info->sections[out_section_header.sh_link].debug_section;
386 gelf_update_shdr(out_section, &out_section_header);
391 static struct poptOption optionsTable[] = {
392 { "output-dir", 'o', POPT_ARG_STRING, &output_dir, 0,
393 "directory to store result", "/usr/lib/debug" },
394 { "strip-debug", 'g', POPT_ARG_NONE, &keep_strtab, 0,
395 "Remove debugging symbols only, keep symbols", 0 },
396 { "unstrip-info", 'u', POPT_ARG_NONE, &add_unstrip_info, 0,
397 "Add unstripping information to the debug file", 0 },
399 { NULL, 0, 0, NULL, 0 }
403 main (int argc, char *argv[])
407 const char *origname;
409 char *debugname, *strippedname;
410 DebugLink *debuglink;
411 poptContext optCon; /* context for parsing command-line options */
414 struct stat stat_buf;
416 optCon = poptGetContext("striptofile", argc, (const char **)argv,
419 while ((nextopt = poptGetNextOpt (optCon)) > 0 || nextopt == POPT_ERROR_BADOPT)
424 fprintf (stderr, "Error on option %s: %s.\nRun '%s --help' to see a full list of available command line options.\n",
425 poptBadOption (optCon, 0),
426 poptStrerror (nextopt),
431 args = poptGetArgs (optCon);
432 if (args == NULL || args[0] == NULL || args[1] != NULL)
434 poptPrintHelp(optCon, stdout, 0);
442 origname_base = path_basename (origname);
443 debugname = strconcat (output_dir, "/", origname_base, ".debug", NULL);
444 free (origname_base);
447 debugname = strconcat (origname, ".debug", NULL);
449 strippedname = strconcat (origname, ".XXXXXX", NULL);
451 if (elf_version(EV_CURRENT) == EV_NONE)
453 fprintf (stderr, "library out of date\n");
457 fd = open (origname, O_RDONLY);
460 fprintf (stderr, "Failed to open input file: %s\n", origname);
464 elf = elf_begin (fd, ELF_C_READ, NULL);
467 fprintf (stderr, "Failed to elf_begin input file: %s\n", origname);
471 /* Create debug file: */
472 out = open (debugname, O_RDWR | O_TRUNC | O_CREAT, 0644);
475 fprintf (stderr, "Failed to open output file: %s\n", debugname);
479 out_elf = elf_begin (out, ELF_C_WRITE, NULL);
482 fprintf (stderr, "Failed to elf_begin output file: %s\n", debugname);
486 copy_debuginfo_to_file (elf, out_elf);
488 elf_update (out_elf, ELF_C_WRITE);
492 debuglink = malloc (sizeof (DebugLink));
493 debuglink->filename = path_basename (debugname);
494 debuglink->checksum = crc32_file (debugname);
496 /* Create stripped file: */
497 out = mkstemp (strippedname);
500 fprintf (stderr, "Failed to open output file: %s\n", strippedname);
504 /* Copy access rights */
505 if (fstat(fd, &stat_buf) == 0)
506 fchmod(out, stat_buf.st_mode);
508 out_elf = elf_begin (out, ELF_C_WRITE, NULL);
511 fprintf (stderr, "Failed to elf_begin output file: %s\n", strippedname);
515 strip_to_file (elf, out_elf, debuglink);
517 elf_update (out_elf, ELF_C_WRITE);
525 if (rename (strippedname, origname) != 0)
526 fprintf(stderr, "unable to write to %s\n", origname);
528 unlink (strippedname);
530 poptFreeContext (optCon);