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