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