1/* simple-object.c -- simple routines to read and write object files.
2 Copyright (C) 2010-2024 Free Software Foundation, Inc.
3 Written by Ian Lance Taylor, Google.
4
5This program is free software; you can redistribute it and/or modify it
6under the terms of the GNU General Public License as published by the
7Free Software Foundation; either version 2, or (at your option) any
8later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, 51 Franklin Street - Fifth Floor,
18Boston, MA 02110-1301, USA. */
19
20#include "config.h"
21#include "libiberty.h"
22#include "simple-object.h"
23
24#include <errno.h>
25#include <fcntl.h>
26
27#ifdef HAVE_STDLIB_H
28#include <stdlib.h>
29#endif
30
31#ifdef HAVE_STDINT_H
32#include <stdint.h>
33#endif
34
35#ifdef HAVE_STRING_H
36#include <string.h>
37#endif
38
39#ifdef HAVE_INTTYPES_H
40#include <inttypes.h>
41#endif
42
43#ifndef SEEK_SET
44#define SEEK_SET 0
45#endif
46
47#ifndef O_BINARY
48#define O_BINARY 0
49#endif
50
51#include "simple-object-common.h"
52
53/* The known object file formats. */
54
55static const struct simple_object_functions * const format_functions[] =
56{
57 &simple_object_elf_functions,
58 &simple_object_mach_o_functions,
59 &simple_object_coff_functions,
60 &simple_object_xcoff_functions
61};
62
63/* Read data from a file using the simple_object error reporting
64 conventions. */
65
66int
67simple_object_internal_read (int descriptor, off_t offset,
68 unsigned char *buffer, size_t size,
69 const char **errmsg, int *err)
70{
71 if (lseek (fd: descriptor, offset: offset, SEEK_SET) < 0)
72 {
73 *errmsg = "lseek";
74 *err = errno;
75 return 0;
76 }
77
78 do
79 {
80 ssize_t got = read (fd: descriptor, buf: buffer, nbytes: size);
81 if (got == 0)
82 break;
83 else if (got > 0)
84 {
85 buffer += got;
86 size -= got;
87 }
88 else if (errno != EINTR)
89 {
90 *errmsg = "read";
91 *err = errno;
92 return 0;
93 }
94 }
95 while (size > 0);
96
97 if (size > 0)
98 {
99 *errmsg = "file too short";
100 *err = 0;
101 return 0;
102 }
103
104 return 1;
105}
106
107/* Write data to a file using the simple_object error reporting
108 conventions. */
109
110int
111simple_object_internal_write (int descriptor, off_t offset,
112 const unsigned char *buffer, size_t size,
113 const char **errmsg, int *err)
114{
115 if (lseek (fd: descriptor, offset: offset, SEEK_SET) < 0)
116 {
117 *errmsg = "lseek";
118 *err = errno;
119 return 0;
120 }
121
122 do
123 {
124 ssize_t wrote = write (fd: descriptor, buf: buffer, n: size);
125 if (wrote == 0)
126 break;
127 else if (wrote > 0)
128 {
129 buffer += wrote;
130 size -= wrote;
131 }
132 else if (errno != EINTR)
133 {
134 *errmsg = "write";
135 *err = errno;
136 return 0;
137 }
138 }
139 while (size > 0);
140
141 if (size > 0)
142 {
143 *errmsg = "short write";
144 *err = 0;
145 return 0;
146 }
147
148 return 1;
149}
150
151/* Open for read. */
152
153simple_object_read *
154simple_object_start_read (int descriptor, off_t offset,
155 const char *segment_name, const char **errmsg,
156 int *err)
157{
158 unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN];
159 size_t len, i;
160
161 if (!simple_object_internal_read (descriptor, offset, buffer: header,
162 SIMPLE_OBJECT_MATCH_HEADER_LEN,
163 errmsg, err))
164 return NULL;
165
166 len = sizeof (format_functions) / sizeof (format_functions[0]);
167 for (i = 0; i < len; ++i)
168 {
169 void *data;
170
171 data = format_functions[i]->match (header, descriptor, offset,
172 segment_name, errmsg, err);
173 if (data != NULL)
174 {
175 simple_object_read *ret;
176
177 ret = XNEW (simple_object_read);
178 ret->descriptor = descriptor;
179 ret->offset = offset;
180 ret->functions = format_functions[i];
181 ret->data = data;
182 return ret;
183 }
184 }
185
186 *errmsg = "file not recognized";
187 *err = 0;
188 return NULL;
189}
190
191/* Find all sections. */
192
193const char *
194simple_object_find_sections (simple_object_read *sobj,
195 int (*pfn) (void *, const char *, off_t, off_t),
196 void *data,
197 int *err)
198{
199 return sobj->functions->find_sections (sobj, pfn, data, err);
200}
201
202/* Internal data passed to find_one_section. */
203
204struct find_one_section_data
205{
206 /* The section we are looking for. */
207 const char *name;
208 /* Where to store the section offset. */
209 off_t *offset;
210 /* Where to store the section length. */
211 off_t *length;
212 /* Set if the name is found. */
213 int found;
214};
215
216/* Internal function passed to find_sections. */
217
218static int
219find_one_section (void *data, const char *name, off_t offset, off_t length)
220{
221 struct find_one_section_data *fosd = (struct find_one_section_data *) data;
222
223 if (strcmp (s1: name, s2: fosd->name) != 0)
224 return 1;
225
226 *fosd->offset = offset;
227 *fosd->length = length;
228 fosd->found = 1;
229
230 /* Stop iteration. */
231 return 0;
232}
233
234/* Find a section. */
235
236int
237simple_object_find_section (simple_object_read *sobj, const char *name,
238 off_t *offset, off_t *length,
239 const char **errmsg, int *err)
240{
241 struct find_one_section_data fosd;
242
243 fosd.name = name;
244 fosd.offset = offset;
245 fosd.length = length;
246 fosd.found = 0;
247
248 *errmsg = simple_object_find_sections (sobj, pfn: find_one_section,
249 data: (void *) &fosd, err);
250 if (*errmsg != NULL)
251 return 0;
252 if (!fosd.found)
253 return 0;
254 return 1;
255}
256
257/* Callback to identify and rename LTO debug sections by name.
258 Returns non-NULL if NAME is a LTO debug section, NULL if not.
259 If RENAME is true it will rename LTO debug sections to non-LTO
260 ones. */
261
262static char *
263handle_lto_debug_sections (const char *name, int rename)
264{
265 char *newname = rename ? XCNEWVEC (char, strlen (name) + 1)
266 : xstrdup (name);
267
268 /* ??? So we can't use .gnu.lto_ prefixed sections as the assembler
269 complains about bogus section flags. Which means we need to arrange
270 for that to be fixed or .gnu.debuglto_ marked as SHF_EXCLUDE (to make
271 fat lto object tooling work for the fat part). */
272 /* Also include corresponding reloc sections. */
273 if (strncmp (s1: name, s2: ".rela", n: sizeof (".rela") - 1) == 0)
274 {
275 if (rename)
276 strncpy (dest: newname, src: name, n: sizeof (".rela") - 1);
277 name += sizeof (".rela") - 1;
278 }
279 else if (strncmp (s1: name, s2: ".rel", n: sizeof (".rel") - 1) == 0)
280 {
281 if (rename)
282 strncpy (dest: newname, src: name, n: sizeof (".rel") - 1);
283 name += sizeof (".rel") - 1;
284 }
285 /* ??? For now this handles both .gnu.lto_ and .gnu.debuglto_ prefixed
286 sections. */
287 /* Copy LTO debug sections and rename them to their non-LTO name. */
288 if (strncmp (s1: name, s2: ".gnu.debuglto_", n: sizeof (".gnu.debuglto_") - 1) == 0)
289 return rename ? strcat (dest: newname, src: name + sizeof (".gnu.debuglto_") - 1) : newname;
290 else if (strncmp (s1: name, s2: ".gnu.lto_.debug_",
291 n: sizeof (".gnu.lto_.debug_") -1) == 0)
292 return rename ? strcat (dest: newname, src: name + sizeof (".gnu.lto_") - 1) : newname;
293 /* Copy over .note.GNU-stack section under the same name if present. */
294 else if (strcmp (s1: name, s2: ".note.GNU-stack") == 0)
295 return strcpy (dest: newname, src: name);
296 /* Copy over .note.gnu.property section under the same name if present. */
297 else if (strcmp (s1: name, s2: ".note.gnu.property") == 0)
298 return strcpy (dest: newname, src: name);
299 /* Copy over .comment section under the same name if present. Solaris
300 ld uses them to relax its checking of ELF gABI access rules for
301 COMDAT sections in objects produced by GCC. */
302 else if (strcmp (s1: name, s2: ".comment") == 0)
303 return strcpy (dest: newname, src: name);
304 /* Copy over .GCC.command.line section under the same name if present. */
305 else if (strcmp (s1: name, s2: ".GCC.command.line") == 0)
306 return strcpy (dest: newname, src: name);
307 /* Copy over .ctf section under the same name if present. */
308 else if (strcmp (s1: name, s2: ".ctf") == 0)
309 return strcpy (dest: newname, src: name);
310 /* Copy over .BTF section under the same name if present. */
311 else if (strcmp (s1: name, s2: ".BTF") == 0)
312 return strcpy (dest: newname, src: name);
313 free (ptr: newname);
314 return NULL;
315}
316
317/* Wrapper for handle_lto_debug_sections. */
318
319static char *
320handle_lto_debug_sections_rename (const char *name)
321{
322 return handle_lto_debug_sections (name, rename: 1);
323}
324
325/* Wrapper for handle_lto_debug_sections. */
326
327static char *
328handle_lto_debug_sections_norename (const char *name)
329{
330 return handle_lto_debug_sections (name, rename: 0);
331}
332
333/* Copy LTO debug sections. */
334
335const char *
336simple_object_copy_lto_debug_sections (simple_object_read *sobj,
337 const char *dest, int *err, int rename)
338{
339 const char *errmsg;
340 simple_object_write *dest_sobj;
341 simple_object_attributes *attrs;
342 int outfd;
343
344 if (! sobj->functions->copy_lto_debug_sections)
345 {
346 *err = EINVAL;
347 return "simple_object_copy_lto_debug_sections not implemented";
348 }
349
350 attrs = simple_object_fetch_attributes (simple_object: sobj, errmsg: &errmsg, err);
351 if (! attrs)
352 return errmsg;
353 dest_sobj = simple_object_start_write (attrs, NULL, errmsg: &errmsg, err);
354 simple_object_release_attributes (attrs);
355 if (! dest_sobj)
356 return errmsg;
357
358 errmsg = sobj->functions->copy_lto_debug_sections
359 (sobj, dest_sobj,
360 rename ? handle_lto_debug_sections_rename
361 : handle_lto_debug_sections_norename, err);
362 if (errmsg)
363 {
364 simple_object_release_write (dest_sobj);
365 return errmsg;
366 }
367
368 outfd = open (file: dest, O_CREAT|O_WRONLY|O_TRUNC|O_BINARY, 00777);
369 if (outfd == -1)
370 {
371 *err = errno;
372 simple_object_release_write (dest_sobj);
373 return "open failed";
374 }
375
376 errmsg = simple_object_write_to_file (simple_object: dest_sobj, descriptor: outfd, err);
377 close (fd: outfd);
378 if (errmsg)
379 {
380 simple_object_release_write (dest_sobj);
381 return errmsg;
382 }
383
384 simple_object_release_write (dest_sobj);
385 return NULL;
386}
387
388/* Fetch attributes. */
389
390simple_object_attributes *
391simple_object_fetch_attributes (simple_object_read *sobj, const char **errmsg,
392 int *err)
393{
394 void *data;
395 simple_object_attributes *ret;
396
397 data = sobj->functions->fetch_attributes (sobj, errmsg, err);
398 if (data == NULL)
399 return NULL;
400 ret = XNEW (simple_object_attributes);
401 ret->functions = sobj->functions;
402 ret->data = data;
403 return ret;
404}
405
406/* Release an simple_object_read. */
407
408void
409simple_object_release_read (simple_object_read *sobj)
410{
411 sobj->functions->release_read (sobj->data);
412 XDELETE (sobj);
413}
414
415/* Merge attributes. */
416
417const char *
418simple_object_attributes_merge (simple_object_attributes *to,
419 simple_object_attributes *from,
420 int *err)
421{
422 if (to->functions != from->functions)
423 {
424 *err = 0;
425 return "different object file format";
426 }
427 return to->functions->attributes_merge (to->data, from->data, err);
428}
429
430/* Release an attributes structure. */
431
432void
433simple_object_release_attributes (simple_object_attributes *attrs)
434{
435 attrs->functions->release_attributes (attrs->data);
436 XDELETE (attrs);
437}
438
439/* Start creating an object file. */
440
441simple_object_write *
442simple_object_start_write (simple_object_attributes *attrs,
443 const char *segment_name, const char **errmsg,
444 int *err)
445{
446 void *data;
447 simple_object_write *ret;
448
449 data = attrs->functions->start_write (attrs->data, errmsg, err);
450 if (data == NULL)
451 return NULL;
452 ret = XNEW (simple_object_write);
453 ret->functions = attrs->functions;
454 ret->segment_name = segment_name ? xstrdup (segment_name) : NULL;
455 ret->sections = NULL;
456 ret->last_section = NULL;
457 ret->data = data;
458 return ret;
459}
460
461/* Start creating a section. */
462
463simple_object_write_section *
464simple_object_write_create_section (simple_object_write *sobj, const char *name,
465 unsigned int align,
466 const char **errmsg ATTRIBUTE_UNUSED,
467 int *err ATTRIBUTE_UNUSED)
468{
469 simple_object_write_section *ret;
470
471 ret = XNEW (simple_object_write_section);
472 ret->next = NULL;
473 ret->name = xstrdup (name);
474 ret->align = align;
475 ret->buffers = NULL;
476 ret->last_buffer = NULL;
477
478 if (sobj->last_section == NULL)
479 {
480 sobj->sections = ret;
481 sobj->last_section = ret;
482 }
483 else
484 {
485 sobj->last_section->next = ret;
486 sobj->last_section = ret;
487 }
488
489 return ret;
490}
491
492/* Add data to a section. */
493
494const char *
495simple_object_write_add_data (simple_object_write *sobj ATTRIBUTE_UNUSED,
496 simple_object_write_section *section,
497 const void *buffer,
498 size_t size, int copy,
499 int *err ATTRIBUTE_UNUSED)
500{
501 struct simple_object_write_section_buffer *wsb;
502
503 wsb = XNEW (struct simple_object_write_section_buffer);
504 wsb->next = NULL;
505 wsb->size = size;
506
507 if (!copy)
508 {
509 wsb->buffer = buffer;
510 wsb->free_buffer = NULL;
511 }
512 else
513 {
514 wsb->free_buffer = (void *) XNEWVEC (char, size);
515 memcpy (dest: wsb->free_buffer, src: buffer, n: size);
516 wsb->buffer = wsb->free_buffer;
517 }
518
519 if (section->last_buffer == NULL)
520 {
521 section->buffers = wsb;
522 section->last_buffer = wsb;
523 }
524 else
525 {
526 section->last_buffer->next = wsb;
527 section->last_buffer = wsb;
528 }
529
530 return NULL;
531}
532
533/* Write the complete object file. */
534
535const char *
536simple_object_write_to_file (simple_object_write *sobj, int descriptor,
537 int *err)
538{
539 return sobj->functions->write_to_file (sobj, descriptor, err);
540}
541
542/* Release an simple_object_write. */
543
544void
545simple_object_release_write (simple_object_write *sobj)
546{
547 simple_object_write_section *section;
548
549 free (ptr: sobj->segment_name);
550
551 section = sobj->sections;
552 while (section != NULL)
553 {
554 struct simple_object_write_section_buffer *buffer;
555 simple_object_write_section *next_section;
556
557 buffer = section->buffers;
558 while (buffer != NULL)
559 {
560 struct simple_object_write_section_buffer *next_buffer;
561
562 if (buffer->free_buffer != NULL)
563 XDELETEVEC (buffer->free_buffer);
564 next_buffer = buffer->next;
565 XDELETE (buffer);
566 buffer = next_buffer;
567 }
568
569 next_section = section->next;
570 free (ptr: section->name);
571 XDELETE (section);
572 section = next_section;
573 }
574
575 sobj->functions->release_write (sobj->data);
576 XDELETE (sobj);
577}
578

source code of libiberty/simple-object.c