xref: /netbsd-src/external/gpl3/gdb/dist/libiberty/simple-object.c (revision 7e120ff03ede3fe64e2c8620c01465d528502ddb)
198b9484cSchristos /* simple-object.c -- simple routines to read and write object files.
2*7e120ff0Schristos    Copyright (C) 2010-2024 Free Software Foundation, Inc.
398b9484cSchristos    Written by Ian Lance Taylor, Google.
498b9484cSchristos 
598b9484cSchristos This program is free software; you can redistribute it and/or modify it
698b9484cSchristos under the terms of the GNU General Public License as published by the
798b9484cSchristos Free Software Foundation; either version 2, or (at your option) any
898b9484cSchristos later version.
998b9484cSchristos 
1098b9484cSchristos This program is distributed in the hope that it will be useful,
1198b9484cSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of
1298b9484cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1398b9484cSchristos GNU General Public License for more details.
1498b9484cSchristos 
1598b9484cSchristos You should have received a copy of the GNU General Public License
1698b9484cSchristos along with this program; if not, write to the Free Software
1798b9484cSchristos Foundation, 51 Franklin Street - Fifth Floor,
1898b9484cSchristos Boston, MA 02110-1301, USA.  */
1998b9484cSchristos 
2098b9484cSchristos #include "config.h"
2198b9484cSchristos #include "libiberty.h"
2298b9484cSchristos #include "simple-object.h"
2398b9484cSchristos 
2498b9484cSchristos #include <errno.h>
254559860eSchristos #include <fcntl.h>
2698b9484cSchristos 
2798b9484cSchristos #ifdef HAVE_STDLIB_H
2898b9484cSchristos #include <stdlib.h>
2998b9484cSchristos #endif
3098b9484cSchristos 
3198b9484cSchristos #ifdef HAVE_STDINT_H
3298b9484cSchristos #include <stdint.h>
3398b9484cSchristos #endif
3498b9484cSchristos 
3598b9484cSchristos #ifdef HAVE_STRING_H
3698b9484cSchristos #include <string.h>
3798b9484cSchristos #endif
3898b9484cSchristos 
3998b9484cSchristos #ifdef HAVE_INTTYPES_H
4098b9484cSchristos #include <inttypes.h>
4198b9484cSchristos #endif
4298b9484cSchristos 
4398b9484cSchristos #ifndef SEEK_SET
4498b9484cSchristos #define SEEK_SET 0
4598b9484cSchristos #endif
4698b9484cSchristos 
478dffb485Schristos #ifndef O_BINARY
488dffb485Schristos #define O_BINARY 0
498dffb485Schristos #endif
508dffb485Schristos 
5198b9484cSchristos #include "simple-object-common.h"
5298b9484cSchristos 
5398b9484cSchristos /* The known object file formats.  */
5498b9484cSchristos 
5598b9484cSchristos static const struct simple_object_functions * const format_functions[] =
5698b9484cSchristos {
5798b9484cSchristos   &simple_object_elf_functions,
5898b9484cSchristos   &simple_object_mach_o_functions,
59a2e2270fSchristos   &simple_object_coff_functions,
60a2e2270fSchristos   &simple_object_xcoff_functions
6198b9484cSchristos };
6298b9484cSchristos 
6398b9484cSchristos /* Read data from a file using the simple_object error reporting
6498b9484cSchristos    conventions.  */
6598b9484cSchristos 
6698b9484cSchristos int
6798b9484cSchristos simple_object_internal_read (int descriptor, off_t offset,
6898b9484cSchristos 			     unsigned char *buffer, size_t size,
6998b9484cSchristos 			     const char **errmsg, int *err)
7098b9484cSchristos {
7198b9484cSchristos   if (lseek (descriptor, offset, SEEK_SET) < 0)
7298b9484cSchristos     {
7398b9484cSchristos       *errmsg = "lseek";
7498b9484cSchristos       *err = errno;
7598b9484cSchristos       return 0;
7698b9484cSchristos     }
7798b9484cSchristos 
78837edd6bSchristos   do
79837edd6bSchristos     {
80837edd6bSchristos       ssize_t got = read (descriptor, buffer, size);
81837edd6bSchristos       if (got == 0)
82837edd6bSchristos 	break;
83837edd6bSchristos       else if (got > 0)
84837edd6bSchristos 	{
85837edd6bSchristos 	  buffer += got;
86837edd6bSchristos 	  size -= got;
87837edd6bSchristos 	}
88837edd6bSchristos       else if (errno != EINTR)
8998b9484cSchristos 	{
9098b9484cSchristos 	  *errmsg = "read";
9198b9484cSchristos 	  *err = errno;
9298b9484cSchristos 	  return 0;
9398b9484cSchristos 	}
94837edd6bSchristos     }
95837edd6bSchristos   while (size > 0);
9698b9484cSchristos 
97837edd6bSchristos   if (size > 0)
9898b9484cSchristos     {
9998b9484cSchristos       *errmsg = "file too short";
10098b9484cSchristos       *err = 0;
10198b9484cSchristos       return 0;
10298b9484cSchristos     }
10398b9484cSchristos 
10498b9484cSchristos   return 1;
10598b9484cSchristos }
10698b9484cSchristos 
10798b9484cSchristos /* Write data to a file using the simple_object error reporting
10898b9484cSchristos    conventions.  */
10998b9484cSchristos 
11098b9484cSchristos int
11198b9484cSchristos simple_object_internal_write (int descriptor, off_t offset,
11298b9484cSchristos 			      const unsigned char *buffer, size_t size,
11398b9484cSchristos 			      const char **errmsg, int *err)
11498b9484cSchristos {
11598b9484cSchristos   if (lseek (descriptor, offset, SEEK_SET) < 0)
11698b9484cSchristos     {
11798b9484cSchristos       *errmsg = "lseek";
11898b9484cSchristos       *err = errno;
11998b9484cSchristos       return 0;
12098b9484cSchristos     }
12198b9484cSchristos 
122837edd6bSchristos   do
123837edd6bSchristos     {
124837edd6bSchristos       ssize_t wrote = write (descriptor, buffer, size);
125837edd6bSchristos       if (wrote == 0)
126837edd6bSchristos 	break;
127837edd6bSchristos       else if (wrote > 0)
128837edd6bSchristos 	{
129837edd6bSchristos 	  buffer += wrote;
130837edd6bSchristos 	  size -= wrote;
131837edd6bSchristos 	}
132837edd6bSchristos       else if (errno != EINTR)
13398b9484cSchristos 	{
13498b9484cSchristos 	  *errmsg = "write";
13598b9484cSchristos 	  *err = errno;
13698b9484cSchristos 	  return 0;
13798b9484cSchristos 	}
138837edd6bSchristos     }
139837edd6bSchristos   while (size > 0);
14098b9484cSchristos 
141837edd6bSchristos   if (size > 0)
14298b9484cSchristos     {
14398b9484cSchristos       *errmsg = "short write";
14498b9484cSchristos       *err = 0;
14598b9484cSchristos       return 0;
14698b9484cSchristos     }
14798b9484cSchristos 
14898b9484cSchristos   return 1;
14998b9484cSchristos }
15098b9484cSchristos 
15198b9484cSchristos /* Open for read.  */
15298b9484cSchristos 
15398b9484cSchristos simple_object_read *
15498b9484cSchristos simple_object_start_read (int descriptor, off_t offset,
15598b9484cSchristos 			  const char *segment_name, const char **errmsg,
15698b9484cSchristos 			  int *err)
15798b9484cSchristos {
15898b9484cSchristos   unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN];
15998b9484cSchristos   size_t len, i;
16098b9484cSchristos 
16198b9484cSchristos   if (!simple_object_internal_read (descriptor, offset, header,
16298b9484cSchristos 				    SIMPLE_OBJECT_MATCH_HEADER_LEN,
16398b9484cSchristos 				    errmsg, err))
16498b9484cSchristos     return NULL;
16598b9484cSchristos 
16698b9484cSchristos   len = sizeof (format_functions) / sizeof (format_functions[0]);
16798b9484cSchristos   for (i = 0; i < len; ++i)
16898b9484cSchristos     {
16998b9484cSchristos       void *data;
17098b9484cSchristos 
17198b9484cSchristos       data = format_functions[i]->match (header, descriptor, offset,
17298b9484cSchristos 					 segment_name, errmsg, err);
17398b9484cSchristos       if (data != NULL)
17498b9484cSchristos 	{
17598b9484cSchristos 	  simple_object_read *ret;
17698b9484cSchristos 
17798b9484cSchristos 	  ret = XNEW (simple_object_read);
17898b9484cSchristos 	  ret->descriptor = descriptor;
17998b9484cSchristos 	  ret->offset = offset;
18098b9484cSchristos 	  ret->functions = format_functions[i];
18198b9484cSchristos 	  ret->data = data;
18298b9484cSchristos 	  return ret;
18398b9484cSchristos 	}
18498b9484cSchristos     }
18598b9484cSchristos 
18698b9484cSchristos   *errmsg = "file not recognized";
18798b9484cSchristos   *err = 0;
18898b9484cSchristos   return NULL;
18998b9484cSchristos }
19098b9484cSchristos 
19198b9484cSchristos /* Find all sections.  */
19298b9484cSchristos 
19398b9484cSchristos const char *
19498b9484cSchristos simple_object_find_sections (simple_object_read *sobj,
19598b9484cSchristos 			     int (*pfn) (void *, const char *, off_t, off_t),
19698b9484cSchristos 			     void *data,
19798b9484cSchristos 			     int *err)
19898b9484cSchristos {
19998b9484cSchristos   return sobj->functions->find_sections (sobj, pfn, data, err);
20098b9484cSchristos }
20198b9484cSchristos 
20298b9484cSchristos /* Internal data passed to find_one_section.  */
20398b9484cSchristos 
20498b9484cSchristos struct find_one_section_data
20598b9484cSchristos {
20698b9484cSchristos   /* The section we are looking for.  */
20798b9484cSchristos   const char *name;
20898b9484cSchristos   /* Where to store the section offset.  */
20998b9484cSchristos   off_t *offset;
21098b9484cSchristos   /* Where to store the section length.  */
21198b9484cSchristos   off_t *length;
21298b9484cSchristos   /* Set if the name is found.  */
21398b9484cSchristos   int found;
21498b9484cSchristos };
21598b9484cSchristos 
21698b9484cSchristos /* Internal function passed to find_sections.  */
21798b9484cSchristos 
21898b9484cSchristos static int
21998b9484cSchristos find_one_section (void *data, const char *name, off_t offset, off_t length)
22098b9484cSchristos {
22198b9484cSchristos   struct find_one_section_data *fosd = (struct find_one_section_data *) data;
22298b9484cSchristos 
22398b9484cSchristos   if (strcmp (name, fosd->name) != 0)
22498b9484cSchristos     return 1;
22598b9484cSchristos 
22698b9484cSchristos   *fosd->offset = offset;
22798b9484cSchristos   *fosd->length = length;
22898b9484cSchristos   fosd->found = 1;
22998b9484cSchristos 
23098b9484cSchristos   /* Stop iteration.  */
23198b9484cSchristos   return 0;
23298b9484cSchristos }
23398b9484cSchristos 
23498b9484cSchristos /* Find a section.  */
23598b9484cSchristos 
23698b9484cSchristos int
23798b9484cSchristos simple_object_find_section (simple_object_read *sobj, const char *name,
23898b9484cSchristos 			    off_t *offset, off_t *length,
23998b9484cSchristos 			    const char **errmsg, int *err)
24098b9484cSchristos {
24198b9484cSchristos   struct find_one_section_data fosd;
24298b9484cSchristos 
24398b9484cSchristos   fosd.name = name;
24498b9484cSchristos   fosd.offset = offset;
24598b9484cSchristos   fosd.length = length;
24698b9484cSchristos   fosd.found = 0;
24798b9484cSchristos 
24898b9484cSchristos   *errmsg = simple_object_find_sections (sobj, find_one_section,
24998b9484cSchristos 					 (void *) &fosd, err);
25098b9484cSchristos   if (*errmsg != NULL)
25198b9484cSchristos     return 0;
25298b9484cSchristos   if (!fosd.found)
25398b9484cSchristos     return 0;
25498b9484cSchristos   return 1;
25598b9484cSchristos }
25698b9484cSchristos 
2574559860eSchristos /* Callback to identify and rename LTO debug sections by name.
2584559860eSchristos    Returns non-NULL if NAME is a LTO debug section, NULL if not.
2594559860eSchristos    If RENAME is true it will rename LTO debug sections to non-LTO
2604559860eSchristos    ones.  */
2614559860eSchristos 
2624559860eSchristos static char *
2634559860eSchristos handle_lto_debug_sections (const char *name, int rename)
2644559860eSchristos {
2654559860eSchristos   char *newname = rename ? XCNEWVEC (char, strlen (name) + 1)
2664559860eSchristos 	  	         : xstrdup (name);
2674559860eSchristos 
2684559860eSchristos   /* ???  So we can't use .gnu.lto_ prefixed sections as the assembler
2694559860eSchristos      complains about bogus section flags.  Which means we need to arrange
2704559860eSchristos      for that to be fixed or .gnu.debuglto_ marked as SHF_EXCLUDE (to make
2714559860eSchristos      fat lto object tooling work for the fat part).  */
2724559860eSchristos   /* Also include corresponding reloc sections.  */
2734559860eSchristos   if (strncmp (name, ".rela", sizeof (".rela") - 1) == 0)
2744559860eSchristos     {
2754559860eSchristos       if (rename)
2764559860eSchristos         strncpy (newname, name, sizeof (".rela") - 1);
2774559860eSchristos       name += sizeof (".rela") - 1;
2784559860eSchristos     }
2794559860eSchristos   else if (strncmp (name, ".rel", sizeof (".rel") - 1) == 0)
2804559860eSchristos     {
2814559860eSchristos       if (rename)
2824559860eSchristos         strncpy (newname, name, sizeof (".rel") - 1);
2834559860eSchristos       name += sizeof (".rel") - 1;
2844559860eSchristos     }
2854559860eSchristos   /* ???  For now this handles both .gnu.lto_ and .gnu.debuglto_ prefixed
2864559860eSchristos      sections.  */
2874559860eSchristos   /* Copy LTO debug sections and rename them to their non-LTO name.  */
2884559860eSchristos   if (strncmp (name, ".gnu.debuglto_", sizeof (".gnu.debuglto_") - 1) == 0)
2894559860eSchristos     return rename ? strcat (newname, name + sizeof (".gnu.debuglto_") - 1) : newname;
2904559860eSchristos   else if (strncmp (name, ".gnu.lto_.debug_",
2914559860eSchristos 		    sizeof (".gnu.lto_.debug_") -1) == 0)
2924559860eSchristos     return rename ? strcat (newname, name + sizeof (".gnu.lto_") - 1) : newname;
2934559860eSchristos   /* Copy over .note.GNU-stack section under the same name if present.  */
2944559860eSchristos   else if (strcmp (name, ".note.GNU-stack") == 0)
2954559860eSchristos     return strcpy (newname, name);
2968dffb485Schristos   /* Copy over .note.gnu.property section under the same name if present.  */
2978dffb485Schristos   else if (strcmp (name, ".note.gnu.property") == 0)
2988dffb485Schristos     return strcpy (newname, name);
2994559860eSchristos   /* Copy over .comment section under the same name if present.  Solaris
3004559860eSchristos      ld uses them to relax its checking of ELF gABI access rules for
3014559860eSchristos      COMDAT sections in objects produced by GCC.  */
3024559860eSchristos   else if (strcmp (name, ".comment") == 0)
3034559860eSchristos     return strcpy (newname, name);
3048dffb485Schristos   /* Copy over .GCC.command.line section under the same name if present.  */
3058dffb485Schristos   else if (strcmp (name, ".GCC.command.line") == 0)
3068dffb485Schristos     return strcpy (newname, name);
3074b169a6bSchristos   /* Copy over .ctf section under the same name if present.  */
3084b169a6bSchristos   else if (strcmp (name, ".ctf") == 0)
3094b169a6bSchristos     return strcpy (newname, name);
3104b169a6bSchristos   /* Copy over .BTF section under the same name if present.  */
3114b169a6bSchristos   else if (strcmp (name, ".BTF") == 0)
3124b169a6bSchristos     return strcpy (newname, name);
3134559860eSchristos   free (newname);
3144559860eSchristos   return NULL;
3154559860eSchristos }
3164559860eSchristos 
3174559860eSchristos /* Wrapper for handle_lto_debug_sections.  */
3184559860eSchristos 
3194559860eSchristos static char *
3204559860eSchristos handle_lto_debug_sections_rename (const char *name)
3214559860eSchristos {
3224559860eSchristos   return handle_lto_debug_sections (name, 1);
3234559860eSchristos }
3244559860eSchristos 
3254559860eSchristos /* Wrapper for handle_lto_debug_sections.  */
3264559860eSchristos 
3274559860eSchristos static char *
3284559860eSchristos handle_lto_debug_sections_norename (const char *name)
3294559860eSchristos {
3304559860eSchristos   return handle_lto_debug_sections (name, 0);
3314559860eSchristos }
3324559860eSchristos 
3334559860eSchristos /* Copy LTO debug sections.  */
3344559860eSchristos 
3354559860eSchristos const char *
3364559860eSchristos simple_object_copy_lto_debug_sections (simple_object_read *sobj,
3374559860eSchristos 				       const char *dest, int *err, int rename)
3384559860eSchristos {
3394559860eSchristos   const char *errmsg;
3404559860eSchristos   simple_object_write *dest_sobj;
3414559860eSchristos   simple_object_attributes *attrs;
3424559860eSchristos   int outfd;
3434559860eSchristos 
3444559860eSchristos   if (! sobj->functions->copy_lto_debug_sections)
3454559860eSchristos     {
3464559860eSchristos       *err = EINVAL;
3474559860eSchristos       return "simple_object_copy_lto_debug_sections not implemented";
3484559860eSchristos     }
3494559860eSchristos 
3504559860eSchristos   attrs = simple_object_fetch_attributes (sobj, &errmsg, err);
3514559860eSchristos   if (! attrs)
3524559860eSchristos     return errmsg;
3534559860eSchristos   dest_sobj = simple_object_start_write (attrs, NULL, &errmsg, err);
3544559860eSchristos   simple_object_release_attributes (attrs);
3554559860eSchristos   if (! dest_sobj)
3564559860eSchristos     return errmsg;
3574559860eSchristos 
3584559860eSchristos   errmsg = sobj->functions->copy_lto_debug_sections
3594559860eSchristos 	 	 (sobj, dest_sobj,
3604559860eSchristos 		  rename ? handle_lto_debug_sections_rename
3614559860eSchristos 			 : handle_lto_debug_sections_norename,  err);
3624559860eSchristos   if (errmsg)
3634559860eSchristos     {
3644559860eSchristos       simple_object_release_write (dest_sobj);
3654559860eSchristos       return errmsg;
3664559860eSchristos     }
3674559860eSchristos 
3688dffb485Schristos   outfd = open (dest, O_CREAT|O_WRONLY|O_TRUNC|O_BINARY, 00777);
3694559860eSchristos   if (outfd == -1)
3704559860eSchristos     {
3714559860eSchristos       *err = errno;
3724559860eSchristos       simple_object_release_write (dest_sobj);
3734559860eSchristos       return "open failed";
3744559860eSchristos     }
3754559860eSchristos 
3764559860eSchristos   errmsg = simple_object_write_to_file (dest_sobj, outfd, err);
3774559860eSchristos   close (outfd);
3784559860eSchristos   if (errmsg)
3794559860eSchristos     {
3804559860eSchristos       simple_object_release_write (dest_sobj);
3814559860eSchristos       return errmsg;
3824559860eSchristos     }
3834559860eSchristos 
3844559860eSchristos   simple_object_release_write (dest_sobj);
3854559860eSchristos   return NULL;
3864559860eSchristos }
3874559860eSchristos 
38898b9484cSchristos /* Fetch attributes.  */
38998b9484cSchristos 
39098b9484cSchristos simple_object_attributes *
39198b9484cSchristos simple_object_fetch_attributes (simple_object_read *sobj, const char **errmsg,
39298b9484cSchristos 				int *err)
39398b9484cSchristos {
39498b9484cSchristos   void *data;
39598b9484cSchristos   simple_object_attributes *ret;
39698b9484cSchristos 
39798b9484cSchristos   data = sobj->functions->fetch_attributes (sobj, errmsg, err);
39898b9484cSchristos   if (data == NULL)
39998b9484cSchristos     return NULL;
40098b9484cSchristos   ret = XNEW (simple_object_attributes);
40198b9484cSchristos   ret->functions = sobj->functions;
40298b9484cSchristos   ret->data = data;
40398b9484cSchristos   return ret;
40498b9484cSchristos }
40598b9484cSchristos 
40698b9484cSchristos /* Release an simple_object_read.  */
40798b9484cSchristos 
40898b9484cSchristos void
40998b9484cSchristos simple_object_release_read (simple_object_read *sobj)
41098b9484cSchristos {
41198b9484cSchristos   sobj->functions->release_read (sobj->data);
41298b9484cSchristos   XDELETE (sobj);
41398b9484cSchristos }
41498b9484cSchristos 
41598b9484cSchristos /* Merge attributes.  */
41698b9484cSchristos 
41798b9484cSchristos const char *
41898b9484cSchristos simple_object_attributes_merge (simple_object_attributes *to,
41998b9484cSchristos 				simple_object_attributes *from,
42098b9484cSchristos 				int *err)
42198b9484cSchristos {
42298b9484cSchristos   if (to->functions != from->functions)
42398b9484cSchristos     {
42498b9484cSchristos       *err = 0;
42598b9484cSchristos       return "different object file format";
42698b9484cSchristos     }
42798b9484cSchristos   return to->functions->attributes_merge (to->data, from->data, err);
42898b9484cSchristos }
42998b9484cSchristos 
43098b9484cSchristos /* Release an attributes structure.  */
43198b9484cSchristos 
43298b9484cSchristos void
43398b9484cSchristos simple_object_release_attributes (simple_object_attributes *attrs)
43498b9484cSchristos {
43598b9484cSchristos   attrs->functions->release_attributes (attrs->data);
43698b9484cSchristos   XDELETE (attrs);
43798b9484cSchristos }
43898b9484cSchristos 
43998b9484cSchristos /* Start creating an object file.  */
44098b9484cSchristos 
44198b9484cSchristos simple_object_write *
44298b9484cSchristos simple_object_start_write (simple_object_attributes *attrs,
44398b9484cSchristos 			   const char *segment_name, const char **errmsg,
44498b9484cSchristos 			   int *err)
44598b9484cSchristos {
44698b9484cSchristos   void *data;
44798b9484cSchristos   simple_object_write *ret;
44898b9484cSchristos 
44998b9484cSchristos   data = attrs->functions->start_write (attrs->data, errmsg, err);
45098b9484cSchristos   if (data == NULL)
45198b9484cSchristos     return NULL;
45298b9484cSchristos   ret = XNEW (simple_object_write);
45398b9484cSchristos   ret->functions = attrs->functions;
4544559860eSchristos   ret->segment_name = segment_name ? xstrdup (segment_name) : NULL;
45598b9484cSchristos   ret->sections = NULL;
45698b9484cSchristos   ret->last_section = NULL;
45798b9484cSchristos   ret->data = data;
45898b9484cSchristos   return ret;
45998b9484cSchristos }
46098b9484cSchristos 
46198b9484cSchristos /* Start creating a section.  */
46298b9484cSchristos 
46398b9484cSchristos simple_object_write_section *
46498b9484cSchristos simple_object_write_create_section (simple_object_write *sobj, const char *name,
46598b9484cSchristos 				    unsigned int align,
46698b9484cSchristos 				    const char **errmsg ATTRIBUTE_UNUSED,
46798b9484cSchristos 				    int *err ATTRIBUTE_UNUSED)
46898b9484cSchristos {
46998b9484cSchristos   simple_object_write_section *ret;
47098b9484cSchristos 
47198b9484cSchristos   ret = XNEW (simple_object_write_section);
47298b9484cSchristos   ret->next = NULL;
47398b9484cSchristos   ret->name = xstrdup (name);
47498b9484cSchristos   ret->align = align;
47598b9484cSchristos   ret->buffers = NULL;
47698b9484cSchristos   ret->last_buffer = NULL;
47798b9484cSchristos 
47898b9484cSchristos   if (sobj->last_section == NULL)
47998b9484cSchristos     {
48098b9484cSchristos       sobj->sections = ret;
48198b9484cSchristos       sobj->last_section = ret;
48298b9484cSchristos     }
48398b9484cSchristos   else
48498b9484cSchristos     {
48598b9484cSchristos       sobj->last_section->next = ret;
48698b9484cSchristos       sobj->last_section = ret;
48798b9484cSchristos     }
48898b9484cSchristos 
48998b9484cSchristos   return ret;
49098b9484cSchristos }
49198b9484cSchristos 
49298b9484cSchristos /* Add data to a section.  */
49398b9484cSchristos 
49498b9484cSchristos const char *
49598b9484cSchristos simple_object_write_add_data (simple_object_write *sobj ATTRIBUTE_UNUSED,
49698b9484cSchristos 			      simple_object_write_section *section,
49798b9484cSchristos 			      const void *buffer,
49898b9484cSchristos 			      size_t size, int copy,
49998b9484cSchristos 			      int *err ATTRIBUTE_UNUSED)
50098b9484cSchristos {
50198b9484cSchristos   struct simple_object_write_section_buffer *wsb;
50298b9484cSchristos 
50398b9484cSchristos   wsb = XNEW (struct simple_object_write_section_buffer);
50498b9484cSchristos   wsb->next = NULL;
50598b9484cSchristos   wsb->size = size;
50698b9484cSchristos 
50798b9484cSchristos   if (!copy)
50898b9484cSchristos     {
50998b9484cSchristos       wsb->buffer = buffer;
51098b9484cSchristos       wsb->free_buffer = NULL;
51198b9484cSchristos     }
51298b9484cSchristos   else
51398b9484cSchristos     {
51498b9484cSchristos       wsb->free_buffer = (void *) XNEWVEC (char, size);
51598b9484cSchristos       memcpy (wsb->free_buffer, buffer, size);
51698b9484cSchristos       wsb->buffer = wsb->free_buffer;
51798b9484cSchristos     }
51898b9484cSchristos 
51998b9484cSchristos   if (section->last_buffer == NULL)
52098b9484cSchristos     {
52198b9484cSchristos       section->buffers = wsb;
52298b9484cSchristos       section->last_buffer = wsb;
52398b9484cSchristos     }
52498b9484cSchristos   else
52598b9484cSchristos     {
52698b9484cSchristos       section->last_buffer->next = wsb;
52798b9484cSchristos       section->last_buffer = wsb;
52898b9484cSchristos     }
52998b9484cSchristos 
53098b9484cSchristos   return NULL;
53198b9484cSchristos }
53298b9484cSchristos 
53398b9484cSchristos /* Write the complete object file.  */
53498b9484cSchristos 
53598b9484cSchristos const char *
53698b9484cSchristos simple_object_write_to_file (simple_object_write *sobj, int descriptor,
53798b9484cSchristos 			     int *err)
53898b9484cSchristos {
53998b9484cSchristos   return sobj->functions->write_to_file (sobj, descriptor, err);
54098b9484cSchristos }
54198b9484cSchristos 
54298b9484cSchristos /* Release an simple_object_write.  */
54398b9484cSchristos 
54498b9484cSchristos void
54598b9484cSchristos simple_object_release_write (simple_object_write *sobj)
54698b9484cSchristos {
54798b9484cSchristos   simple_object_write_section *section;
54898b9484cSchristos 
54998b9484cSchristos   free (sobj->segment_name);
55098b9484cSchristos 
55198b9484cSchristos   section = sobj->sections;
55298b9484cSchristos   while (section != NULL)
55398b9484cSchristos     {
55498b9484cSchristos       struct simple_object_write_section_buffer *buffer;
55598b9484cSchristos       simple_object_write_section *next_section;
55698b9484cSchristos 
55798b9484cSchristos       buffer = section->buffers;
55898b9484cSchristos       while (buffer != NULL)
55998b9484cSchristos 	{
56098b9484cSchristos 	  struct simple_object_write_section_buffer *next_buffer;
56198b9484cSchristos 
56298b9484cSchristos 	  if (buffer->free_buffer != NULL)
56398b9484cSchristos 	    XDELETEVEC (buffer->free_buffer);
56498b9484cSchristos 	  next_buffer = buffer->next;
56598b9484cSchristos 	  XDELETE (buffer);
56698b9484cSchristos 	  buffer = next_buffer;
56798b9484cSchristos 	}
56898b9484cSchristos 
56998b9484cSchristos       next_section = section->next;
57098b9484cSchristos       free (section->name);
57198b9484cSchristos       XDELETE (section);
57298b9484cSchristos       section = next_section;
57398b9484cSchristos     }
57498b9484cSchristos 
57598b9484cSchristos   sobj->functions->release_write (sobj->data);
57698b9484cSchristos   XDELETE (sobj);
57798b9484cSchristos }
578