1*e4b17023SJohn Marino /* simple-object.c -- simple routines to read and write object files.
2*e4b17023SJohn Marino    Copyright 2010 Free Software Foundation, Inc.
3*e4b17023SJohn Marino    Written by Ian Lance Taylor, Google.
4*e4b17023SJohn Marino 
5*e4b17023SJohn Marino This program is free software; you can redistribute it and/or modify it
6*e4b17023SJohn Marino under the terms of the GNU General Public License as published by the
7*e4b17023SJohn Marino Free Software Foundation; either version 2, or (at your option) any
8*e4b17023SJohn Marino later version.
9*e4b17023SJohn Marino 
10*e4b17023SJohn Marino This program is distributed in the hope that it will be useful,
11*e4b17023SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
12*e4b17023SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*e4b17023SJohn Marino GNU General Public License for more details.
14*e4b17023SJohn Marino 
15*e4b17023SJohn Marino You should have received a copy of the GNU General Public License
16*e4b17023SJohn Marino along with this program; if not, write to the Free Software
17*e4b17023SJohn Marino Foundation, 51 Franklin Street - Fifth Floor,
18*e4b17023SJohn Marino Boston, MA 02110-1301, USA.  */
19*e4b17023SJohn Marino 
20*e4b17023SJohn Marino #include "config.h"
21*e4b17023SJohn Marino #include "libiberty.h"
22*e4b17023SJohn Marino #include "simple-object.h"
23*e4b17023SJohn Marino 
24*e4b17023SJohn Marino #include <errno.h>
25*e4b17023SJohn Marino 
26*e4b17023SJohn Marino #ifdef HAVE_STDLIB_H
27*e4b17023SJohn Marino #include <stdlib.h>
28*e4b17023SJohn Marino #endif
29*e4b17023SJohn Marino 
30*e4b17023SJohn Marino #ifdef HAVE_STDINT_H
31*e4b17023SJohn Marino #include <stdint.h>
32*e4b17023SJohn Marino #endif
33*e4b17023SJohn Marino 
34*e4b17023SJohn Marino #ifdef HAVE_STRING_H
35*e4b17023SJohn Marino #include <string.h>
36*e4b17023SJohn Marino #endif
37*e4b17023SJohn Marino 
38*e4b17023SJohn Marino #ifdef HAVE_INTTYPES_H
39*e4b17023SJohn Marino #include <inttypes.h>
40*e4b17023SJohn Marino #endif
41*e4b17023SJohn Marino 
42*e4b17023SJohn Marino #ifndef SEEK_SET
43*e4b17023SJohn Marino #define SEEK_SET 0
44*e4b17023SJohn Marino #endif
45*e4b17023SJohn Marino 
46*e4b17023SJohn Marino #include "simple-object-common.h"
47*e4b17023SJohn Marino 
48*e4b17023SJohn Marino /* The known object file formats.  */
49*e4b17023SJohn Marino 
50*e4b17023SJohn Marino static const struct simple_object_functions * const format_functions[] =
51*e4b17023SJohn Marino {
52*e4b17023SJohn Marino   &simple_object_elf_functions,
53*e4b17023SJohn Marino   &simple_object_mach_o_functions,
54*e4b17023SJohn Marino   &simple_object_coff_functions
55*e4b17023SJohn Marino };
56*e4b17023SJohn Marino 
57*e4b17023SJohn Marino /* Read data from a file using the simple_object error reporting
58*e4b17023SJohn Marino    conventions.  */
59*e4b17023SJohn Marino 
60*e4b17023SJohn Marino int
simple_object_internal_read(int descriptor,off_t offset,unsigned char * buffer,size_t size,const char ** errmsg,int * err)61*e4b17023SJohn Marino simple_object_internal_read (int descriptor, off_t offset,
62*e4b17023SJohn Marino 			     unsigned char *buffer, size_t size,
63*e4b17023SJohn Marino 			     const char **errmsg, int *err)
64*e4b17023SJohn Marino {
65*e4b17023SJohn Marino   ssize_t got;
66*e4b17023SJohn Marino 
67*e4b17023SJohn Marino   if (lseek (descriptor, offset, SEEK_SET) < 0)
68*e4b17023SJohn Marino     {
69*e4b17023SJohn Marino       *errmsg = "lseek";
70*e4b17023SJohn Marino       *err = errno;
71*e4b17023SJohn Marino       return 0;
72*e4b17023SJohn Marino     }
73*e4b17023SJohn Marino 
74*e4b17023SJohn Marino   got = read (descriptor, buffer, size);
75*e4b17023SJohn Marino   if (got < 0)
76*e4b17023SJohn Marino     {
77*e4b17023SJohn Marino       *errmsg = "read";
78*e4b17023SJohn Marino       *err = errno;
79*e4b17023SJohn Marino       return 0;
80*e4b17023SJohn Marino     }
81*e4b17023SJohn Marino 
82*e4b17023SJohn Marino   if ((size_t) got < size)
83*e4b17023SJohn Marino     {
84*e4b17023SJohn Marino       *errmsg = "file too short";
85*e4b17023SJohn Marino       *err = 0;
86*e4b17023SJohn Marino       return 0;
87*e4b17023SJohn Marino     }
88*e4b17023SJohn Marino 
89*e4b17023SJohn Marino   return 1;
90*e4b17023SJohn Marino }
91*e4b17023SJohn Marino 
92*e4b17023SJohn Marino /* Write data to a file using the simple_object error reporting
93*e4b17023SJohn Marino    conventions.  */
94*e4b17023SJohn Marino 
95*e4b17023SJohn Marino int
simple_object_internal_write(int descriptor,off_t offset,const unsigned char * buffer,size_t size,const char ** errmsg,int * err)96*e4b17023SJohn Marino simple_object_internal_write (int descriptor, off_t offset,
97*e4b17023SJohn Marino 			      const unsigned char *buffer, size_t size,
98*e4b17023SJohn Marino 			      const char **errmsg, int *err)
99*e4b17023SJohn Marino {
100*e4b17023SJohn Marino   ssize_t wrote;
101*e4b17023SJohn Marino 
102*e4b17023SJohn Marino   if (lseek (descriptor, offset, SEEK_SET) < 0)
103*e4b17023SJohn Marino     {
104*e4b17023SJohn Marino       *errmsg = "lseek";
105*e4b17023SJohn Marino       *err = errno;
106*e4b17023SJohn Marino       return 0;
107*e4b17023SJohn Marino     }
108*e4b17023SJohn Marino 
109*e4b17023SJohn Marino   wrote = write (descriptor, buffer, size);
110*e4b17023SJohn Marino   if (wrote < 0)
111*e4b17023SJohn Marino     {
112*e4b17023SJohn Marino       *errmsg = "write";
113*e4b17023SJohn Marino       *err = errno;
114*e4b17023SJohn Marino       return 0;
115*e4b17023SJohn Marino     }
116*e4b17023SJohn Marino 
117*e4b17023SJohn Marino   if ((size_t) wrote < size)
118*e4b17023SJohn Marino     {
119*e4b17023SJohn Marino       *errmsg = "short write";
120*e4b17023SJohn Marino       *err = 0;
121*e4b17023SJohn Marino       return 0;
122*e4b17023SJohn Marino     }
123*e4b17023SJohn Marino 
124*e4b17023SJohn Marino   return 1;
125*e4b17023SJohn Marino }
126*e4b17023SJohn Marino 
127*e4b17023SJohn Marino /* Open for read.  */
128*e4b17023SJohn Marino 
129*e4b17023SJohn Marino simple_object_read *
simple_object_start_read(int descriptor,off_t offset,const char * segment_name,const char ** errmsg,int * err)130*e4b17023SJohn Marino simple_object_start_read (int descriptor, off_t offset,
131*e4b17023SJohn Marino 			  const char *segment_name, const char **errmsg,
132*e4b17023SJohn Marino 			  int *err)
133*e4b17023SJohn Marino {
134*e4b17023SJohn Marino   unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN];
135*e4b17023SJohn Marino   size_t len, i;
136*e4b17023SJohn Marino 
137*e4b17023SJohn Marino   if (!simple_object_internal_read (descriptor, offset, header,
138*e4b17023SJohn Marino 				    SIMPLE_OBJECT_MATCH_HEADER_LEN,
139*e4b17023SJohn Marino 				    errmsg, err))
140*e4b17023SJohn Marino     return NULL;
141*e4b17023SJohn Marino 
142*e4b17023SJohn Marino   len = sizeof (format_functions) / sizeof (format_functions[0]);
143*e4b17023SJohn Marino   for (i = 0; i < len; ++i)
144*e4b17023SJohn Marino     {
145*e4b17023SJohn Marino       void *data;
146*e4b17023SJohn Marino 
147*e4b17023SJohn Marino       data = format_functions[i]->match (header, descriptor, offset,
148*e4b17023SJohn Marino 					 segment_name, errmsg, err);
149*e4b17023SJohn Marino       if (data != NULL)
150*e4b17023SJohn Marino 	{
151*e4b17023SJohn Marino 	  simple_object_read *ret;
152*e4b17023SJohn Marino 
153*e4b17023SJohn Marino 	  ret = XNEW (simple_object_read);
154*e4b17023SJohn Marino 	  ret->descriptor = descriptor;
155*e4b17023SJohn Marino 	  ret->offset = offset;
156*e4b17023SJohn Marino 	  ret->functions = format_functions[i];
157*e4b17023SJohn Marino 	  ret->data = data;
158*e4b17023SJohn Marino 	  return ret;
159*e4b17023SJohn Marino 	}
160*e4b17023SJohn Marino     }
161*e4b17023SJohn Marino 
162*e4b17023SJohn Marino   *errmsg = "file not recognized";
163*e4b17023SJohn Marino   *err = 0;
164*e4b17023SJohn Marino   return NULL;
165*e4b17023SJohn Marino }
166*e4b17023SJohn Marino 
167*e4b17023SJohn Marino /* Find all sections.  */
168*e4b17023SJohn Marino 
169*e4b17023SJohn Marino const char *
simple_object_find_sections(simple_object_read * sobj,int (* pfn)(void *,const char *,off_t,off_t),void * data,int * err)170*e4b17023SJohn Marino simple_object_find_sections (simple_object_read *sobj,
171*e4b17023SJohn Marino 			     int (*pfn) (void *, const char *, off_t, off_t),
172*e4b17023SJohn Marino 			     void *data,
173*e4b17023SJohn Marino 			     int *err)
174*e4b17023SJohn Marino {
175*e4b17023SJohn Marino   return sobj->functions->find_sections (sobj, pfn, data, err);
176*e4b17023SJohn Marino }
177*e4b17023SJohn Marino 
178*e4b17023SJohn Marino /* Internal data passed to find_one_section.  */
179*e4b17023SJohn Marino 
180*e4b17023SJohn Marino struct find_one_section_data
181*e4b17023SJohn Marino {
182*e4b17023SJohn Marino   /* The section we are looking for.  */
183*e4b17023SJohn Marino   const char *name;
184*e4b17023SJohn Marino   /* Where to store the section offset.  */
185*e4b17023SJohn Marino   off_t *offset;
186*e4b17023SJohn Marino   /* Where to store the section length.  */
187*e4b17023SJohn Marino   off_t *length;
188*e4b17023SJohn Marino   /* Set if the name is found.  */
189*e4b17023SJohn Marino   int found;
190*e4b17023SJohn Marino };
191*e4b17023SJohn Marino 
192*e4b17023SJohn Marino /* Internal function passed to find_sections.  */
193*e4b17023SJohn Marino 
194*e4b17023SJohn Marino static int
find_one_section(void * data,const char * name,off_t offset,off_t length)195*e4b17023SJohn Marino find_one_section (void *data, const char *name, off_t offset, off_t length)
196*e4b17023SJohn Marino {
197*e4b17023SJohn Marino   struct find_one_section_data *fosd = (struct find_one_section_data *) data;
198*e4b17023SJohn Marino 
199*e4b17023SJohn Marino   if (strcmp (name, fosd->name) != 0)
200*e4b17023SJohn Marino     return 1;
201*e4b17023SJohn Marino 
202*e4b17023SJohn Marino   *fosd->offset = offset;
203*e4b17023SJohn Marino   *fosd->length = length;
204*e4b17023SJohn Marino   fosd->found = 1;
205*e4b17023SJohn Marino 
206*e4b17023SJohn Marino   /* Stop iteration.  */
207*e4b17023SJohn Marino   return 0;
208*e4b17023SJohn Marino }
209*e4b17023SJohn Marino 
210*e4b17023SJohn Marino /* Find a section.  */
211*e4b17023SJohn Marino 
212*e4b17023SJohn Marino int
simple_object_find_section(simple_object_read * sobj,const char * name,off_t * offset,off_t * length,const char ** errmsg,int * err)213*e4b17023SJohn Marino simple_object_find_section (simple_object_read *sobj, const char *name,
214*e4b17023SJohn Marino 			    off_t *offset, off_t *length,
215*e4b17023SJohn Marino 			    const char **errmsg, int *err)
216*e4b17023SJohn Marino {
217*e4b17023SJohn Marino   struct find_one_section_data fosd;
218*e4b17023SJohn Marino 
219*e4b17023SJohn Marino   fosd.name = name;
220*e4b17023SJohn Marino   fosd.offset = offset;
221*e4b17023SJohn Marino   fosd.length = length;
222*e4b17023SJohn Marino   fosd.found = 0;
223*e4b17023SJohn Marino 
224*e4b17023SJohn Marino   *errmsg = simple_object_find_sections (sobj, find_one_section,
225*e4b17023SJohn Marino 					 (void *) &fosd, err);
226*e4b17023SJohn Marino   if (*errmsg != NULL)
227*e4b17023SJohn Marino     return 0;
228*e4b17023SJohn Marino   if (!fosd.found)
229*e4b17023SJohn Marino     return 0;
230*e4b17023SJohn Marino   return 1;
231*e4b17023SJohn Marino }
232*e4b17023SJohn Marino 
233*e4b17023SJohn Marino /* Fetch attributes.  */
234*e4b17023SJohn Marino 
235*e4b17023SJohn Marino simple_object_attributes *
simple_object_fetch_attributes(simple_object_read * sobj,const char ** errmsg,int * err)236*e4b17023SJohn Marino simple_object_fetch_attributes (simple_object_read *sobj, const char **errmsg,
237*e4b17023SJohn Marino 				int *err)
238*e4b17023SJohn Marino {
239*e4b17023SJohn Marino   void *data;
240*e4b17023SJohn Marino   simple_object_attributes *ret;
241*e4b17023SJohn Marino 
242*e4b17023SJohn Marino   data = sobj->functions->fetch_attributes (sobj, errmsg, err);
243*e4b17023SJohn Marino   if (data == NULL)
244*e4b17023SJohn Marino     return NULL;
245*e4b17023SJohn Marino   ret = XNEW (simple_object_attributes);
246*e4b17023SJohn Marino   ret->functions = sobj->functions;
247*e4b17023SJohn Marino   ret->data = data;
248*e4b17023SJohn Marino   return ret;
249*e4b17023SJohn Marino }
250*e4b17023SJohn Marino 
251*e4b17023SJohn Marino /* Release an simple_object_read.  */
252*e4b17023SJohn Marino 
253*e4b17023SJohn Marino void
simple_object_release_read(simple_object_read * sobj)254*e4b17023SJohn Marino simple_object_release_read (simple_object_read *sobj)
255*e4b17023SJohn Marino {
256*e4b17023SJohn Marino   sobj->functions->release_read (sobj->data);
257*e4b17023SJohn Marino   XDELETE (sobj);
258*e4b17023SJohn Marino }
259*e4b17023SJohn Marino 
260*e4b17023SJohn Marino /* Merge attributes.  */
261*e4b17023SJohn Marino 
262*e4b17023SJohn Marino const char *
simple_object_attributes_merge(simple_object_attributes * to,simple_object_attributes * from,int * err)263*e4b17023SJohn Marino simple_object_attributes_merge (simple_object_attributes *to,
264*e4b17023SJohn Marino 				simple_object_attributes *from,
265*e4b17023SJohn Marino 				int *err)
266*e4b17023SJohn Marino {
267*e4b17023SJohn Marino   if (to->functions != from->functions)
268*e4b17023SJohn Marino     {
269*e4b17023SJohn Marino       *err = 0;
270*e4b17023SJohn Marino       return "different object file format";
271*e4b17023SJohn Marino     }
272*e4b17023SJohn Marino   return to->functions->attributes_merge (to->data, from->data, err);
273*e4b17023SJohn Marino }
274*e4b17023SJohn Marino 
275*e4b17023SJohn Marino /* Release an attributes structure.  */
276*e4b17023SJohn Marino 
277*e4b17023SJohn Marino void
simple_object_release_attributes(simple_object_attributes * attrs)278*e4b17023SJohn Marino simple_object_release_attributes (simple_object_attributes *attrs)
279*e4b17023SJohn Marino {
280*e4b17023SJohn Marino   attrs->functions->release_attributes (attrs->data);
281*e4b17023SJohn Marino   XDELETE (attrs);
282*e4b17023SJohn Marino }
283*e4b17023SJohn Marino 
284*e4b17023SJohn Marino /* Start creating an object file.  */
285*e4b17023SJohn Marino 
286*e4b17023SJohn Marino simple_object_write *
simple_object_start_write(simple_object_attributes * attrs,const char * segment_name,const char ** errmsg,int * err)287*e4b17023SJohn Marino simple_object_start_write (simple_object_attributes *attrs,
288*e4b17023SJohn Marino 			   const char *segment_name, const char **errmsg,
289*e4b17023SJohn Marino 			   int *err)
290*e4b17023SJohn Marino {
291*e4b17023SJohn Marino   void *data;
292*e4b17023SJohn Marino   simple_object_write *ret;
293*e4b17023SJohn Marino 
294*e4b17023SJohn Marino   data = attrs->functions->start_write (attrs->data, errmsg, err);
295*e4b17023SJohn Marino   if (data == NULL)
296*e4b17023SJohn Marino     return NULL;
297*e4b17023SJohn Marino   ret = XNEW (simple_object_write);
298*e4b17023SJohn Marino   ret->functions = attrs->functions;
299*e4b17023SJohn Marino   ret->segment_name = xstrdup (segment_name);
300*e4b17023SJohn Marino   ret->sections = NULL;
301*e4b17023SJohn Marino   ret->last_section = NULL;
302*e4b17023SJohn Marino   ret->data = data;
303*e4b17023SJohn Marino   return ret;
304*e4b17023SJohn Marino }
305*e4b17023SJohn Marino 
306*e4b17023SJohn Marino /* Start creating a section.  */
307*e4b17023SJohn Marino 
308*e4b17023SJohn Marino simple_object_write_section *
simple_object_write_create_section(simple_object_write * sobj,const char * name,unsigned int align,const char ** errmsg ATTRIBUTE_UNUSED,int * err ATTRIBUTE_UNUSED)309*e4b17023SJohn Marino simple_object_write_create_section (simple_object_write *sobj, const char *name,
310*e4b17023SJohn Marino 				    unsigned int align,
311*e4b17023SJohn Marino 				    const char **errmsg ATTRIBUTE_UNUSED,
312*e4b17023SJohn Marino 				    int *err ATTRIBUTE_UNUSED)
313*e4b17023SJohn Marino {
314*e4b17023SJohn Marino   simple_object_write_section *ret;
315*e4b17023SJohn Marino 
316*e4b17023SJohn Marino   ret = XNEW (simple_object_write_section);
317*e4b17023SJohn Marino   ret->next = NULL;
318*e4b17023SJohn Marino   ret->name = xstrdup (name);
319*e4b17023SJohn Marino   ret->align = align;
320*e4b17023SJohn Marino   ret->buffers = NULL;
321*e4b17023SJohn Marino   ret->last_buffer = NULL;
322*e4b17023SJohn Marino 
323*e4b17023SJohn Marino   if (sobj->last_section == NULL)
324*e4b17023SJohn Marino     {
325*e4b17023SJohn Marino       sobj->sections = ret;
326*e4b17023SJohn Marino       sobj->last_section = ret;
327*e4b17023SJohn Marino     }
328*e4b17023SJohn Marino   else
329*e4b17023SJohn Marino     {
330*e4b17023SJohn Marino       sobj->last_section->next = ret;
331*e4b17023SJohn Marino       sobj->last_section = ret;
332*e4b17023SJohn Marino     }
333*e4b17023SJohn Marino 
334*e4b17023SJohn Marino   return ret;
335*e4b17023SJohn Marino }
336*e4b17023SJohn Marino 
337*e4b17023SJohn Marino /* Add data to a section.  */
338*e4b17023SJohn Marino 
339*e4b17023SJohn Marino const char *
simple_object_write_add_data(simple_object_write * sobj ATTRIBUTE_UNUSED,simple_object_write_section * section,const void * buffer,size_t size,int copy,int * err ATTRIBUTE_UNUSED)340*e4b17023SJohn Marino simple_object_write_add_data (simple_object_write *sobj ATTRIBUTE_UNUSED,
341*e4b17023SJohn Marino 			      simple_object_write_section *section,
342*e4b17023SJohn Marino 			      const void *buffer,
343*e4b17023SJohn Marino 			      size_t size, int copy,
344*e4b17023SJohn Marino 			      int *err ATTRIBUTE_UNUSED)
345*e4b17023SJohn Marino {
346*e4b17023SJohn Marino   struct simple_object_write_section_buffer *wsb;
347*e4b17023SJohn Marino 
348*e4b17023SJohn Marino   wsb = XNEW (struct simple_object_write_section_buffer);
349*e4b17023SJohn Marino   wsb->next = NULL;
350*e4b17023SJohn Marino   wsb->size = size;
351*e4b17023SJohn Marino 
352*e4b17023SJohn Marino   if (!copy)
353*e4b17023SJohn Marino     {
354*e4b17023SJohn Marino       wsb->buffer = buffer;
355*e4b17023SJohn Marino       wsb->free_buffer = NULL;
356*e4b17023SJohn Marino     }
357*e4b17023SJohn Marino   else
358*e4b17023SJohn Marino     {
359*e4b17023SJohn Marino       wsb->free_buffer = (void *) XNEWVEC (char, size);
360*e4b17023SJohn Marino       memcpy (wsb->free_buffer, buffer, size);
361*e4b17023SJohn Marino       wsb->buffer = wsb->free_buffer;
362*e4b17023SJohn Marino     }
363*e4b17023SJohn Marino 
364*e4b17023SJohn Marino   if (section->last_buffer == NULL)
365*e4b17023SJohn Marino     {
366*e4b17023SJohn Marino       section->buffers = wsb;
367*e4b17023SJohn Marino       section->last_buffer = wsb;
368*e4b17023SJohn Marino     }
369*e4b17023SJohn Marino   else
370*e4b17023SJohn Marino     {
371*e4b17023SJohn Marino       section->last_buffer->next = wsb;
372*e4b17023SJohn Marino       section->last_buffer = wsb;
373*e4b17023SJohn Marino     }
374*e4b17023SJohn Marino 
375*e4b17023SJohn Marino   return NULL;
376*e4b17023SJohn Marino }
377*e4b17023SJohn Marino 
378*e4b17023SJohn Marino /* Write the complete object file.  */
379*e4b17023SJohn Marino 
380*e4b17023SJohn Marino const char *
simple_object_write_to_file(simple_object_write * sobj,int descriptor,int * err)381*e4b17023SJohn Marino simple_object_write_to_file (simple_object_write *sobj, int descriptor,
382*e4b17023SJohn Marino 			     int *err)
383*e4b17023SJohn Marino {
384*e4b17023SJohn Marino   return sobj->functions->write_to_file (sobj, descriptor, err);
385*e4b17023SJohn Marino }
386*e4b17023SJohn Marino 
387*e4b17023SJohn Marino /* Release an simple_object_write.  */
388*e4b17023SJohn Marino 
389*e4b17023SJohn Marino void
simple_object_release_write(simple_object_write * sobj)390*e4b17023SJohn Marino simple_object_release_write (simple_object_write *sobj)
391*e4b17023SJohn Marino {
392*e4b17023SJohn Marino   simple_object_write_section *section;
393*e4b17023SJohn Marino 
394*e4b17023SJohn Marino   free (sobj->segment_name);
395*e4b17023SJohn Marino 
396*e4b17023SJohn Marino   section = sobj->sections;
397*e4b17023SJohn Marino   while (section != NULL)
398*e4b17023SJohn Marino     {
399*e4b17023SJohn Marino       struct simple_object_write_section_buffer *buffer;
400*e4b17023SJohn Marino       simple_object_write_section *next_section;
401*e4b17023SJohn Marino 
402*e4b17023SJohn Marino       buffer = section->buffers;
403*e4b17023SJohn Marino       while (buffer != NULL)
404*e4b17023SJohn Marino 	{
405*e4b17023SJohn Marino 	  struct simple_object_write_section_buffer *next_buffer;
406*e4b17023SJohn Marino 
407*e4b17023SJohn Marino 	  if (buffer->free_buffer != NULL)
408*e4b17023SJohn Marino 	    XDELETEVEC (buffer->free_buffer);
409*e4b17023SJohn Marino 	  next_buffer = buffer->next;
410*e4b17023SJohn Marino 	  XDELETE (buffer);
411*e4b17023SJohn Marino 	  buffer = next_buffer;
412*e4b17023SJohn Marino 	}
413*e4b17023SJohn Marino 
414*e4b17023SJohn Marino       next_section = section->next;
415*e4b17023SJohn Marino       free (section->name);
416*e4b17023SJohn Marino       XDELETE (section);
417*e4b17023SJohn Marino       section = next_section;
418*e4b17023SJohn Marino     }
419*e4b17023SJohn Marino 
420*e4b17023SJohn Marino   sobj->functions->release_write (sobj->data);
421*e4b17023SJohn Marino   XDELETE (sobj);
422*e4b17023SJohn Marino }
423