simple-object.c revision 1.1.1.5 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.5 christos Returns non-NULL if NAME is a LTO debug section, NULL if not.
255 1.1.1.5 christos If RENAME is true it will rename LTO debug sections to non-LTO
256 1.1.1.5 christos ones. */
257 1.1.1.4 christos
258 1.1.1.5 christos static char *
259 1.1.1.5 christos handle_lto_debug_sections (const char *name, int rename)
260 1.1.1.4 christos {
261 1.1.1.5 christos char *newname = rename ? XCNEWVEC (char, strlen (name) + 1)
262 1.1.1.5 christos : xstrdup (name);
263 1.1.1.5 christos
264 1.1.1.4 christos /* ??? So we can't use .gnu.lto_ prefixed sections as the assembler
265 1.1.1.4 christos complains about bogus section flags. Which means we need to arrange
266 1.1.1.4 christos for that to be fixed or .gnu.debuglto_ marked as SHF_EXCLUDE (to make
267 1.1.1.4 christos fat lto object tooling work for the fat part). */
268 1.1.1.5 christos /* Also include corresponding reloc sections. */
269 1.1.1.5 christos if (strncmp (name, ".rela", sizeof (".rela") - 1) == 0)
270 1.1.1.5 christos {
271 1.1.1.5 christos if (rename)
272 1.1.1.5 christos strncpy (newname, name, sizeof (".rela") - 1);
273 1.1.1.5 christos name += sizeof (".rela") - 1;
274 1.1.1.5 christos }
275 1.1.1.5 christos else if (strncmp (name, ".rel", sizeof (".rel") - 1) == 0)
276 1.1.1.5 christos {
277 1.1.1.5 christos if (rename)
278 1.1.1.5 christos strncpy (newname, name, sizeof (".rel") - 1);
279 1.1.1.5 christos name += sizeof (".rel") - 1;
280 1.1.1.5 christos }
281 1.1.1.4 christos /* ??? For now this handles both .gnu.lto_ and .gnu.debuglto_ prefixed
282 1.1.1.4 christos sections. */
283 1.1.1.4 christos /* Copy LTO debug sections and rename them to their non-LTO name. */
284 1.1.1.5 christos if (strncmp (name, ".gnu.debuglto_", sizeof (".gnu.debuglto_") - 1) == 0)
285 1.1.1.5 christos return rename ? strcat (newname, name + sizeof (".gnu.debuglto_") - 1) : newname;
286 1.1.1.5 christos else if (strncmp (name, ".gnu.lto_.debug_",
287 1.1.1.5 christos sizeof (".gnu.lto_.debug_") -1) == 0)
288 1.1.1.5 christos return rename ? strcat (newname, name + sizeof (".gnu.lto_") - 1) : newname;
289 1.1.1.4 christos /* Copy over .note.GNU-stack section under the same name if present. */
290 1.1.1.5 christos else if (strcmp (name, ".note.GNU-stack") == 0)
291 1.1.1.5 christos return strcpy (newname, name);
292 1.1.1.5 christos /* Copy over .comment section under the same name if present. Solaris
293 1.1.1.5 christos ld uses them to relax its checking of ELF gABI access rules for
294 1.1.1.5 christos COMDAT sections in objects produced by GCC. */
295 1.1.1.5 christos else if (strcmp (name, ".comment") == 0)
296 1.1.1.5 christos return strcpy (newname, name);
297 1.1.1.5 christos free (newname);
298 1.1.1.5 christos return NULL;
299 1.1.1.5 christos }
300 1.1.1.5 christos
301 1.1.1.5 christos /* Wrapper for handle_lto_debug_sections. */
302 1.1.1.5 christos
303 1.1.1.5 christos static char *
304 1.1.1.5 christos handle_lto_debug_sections_rename (const char *name)
305 1.1.1.5 christos {
306 1.1.1.5 christos return handle_lto_debug_sections (name, 1);
307 1.1.1.5 christos }
308 1.1.1.5 christos
309 1.1.1.5 christos /* Wrapper for handle_lto_debug_sections. */
310 1.1.1.5 christos
311 1.1.1.5 christos static char *
312 1.1.1.5 christos handle_lto_debug_sections_norename (const char *name)
313 1.1.1.5 christos {
314 1.1.1.5 christos return handle_lto_debug_sections (name, 0);
315 1.1.1.4 christos }
316 1.1.1.4 christos
317 1.1.1.4 christos /* Copy LTO debug sections. */
318 1.1.1.4 christos
319 1.1.1.4 christos const char *
320 1.1.1.4 christos simple_object_copy_lto_debug_sections (simple_object_read *sobj,
321 1.1.1.5 christos const char *dest, int *err, int rename)
322 1.1.1.4 christos {
323 1.1.1.4 christos const char *errmsg;
324 1.1.1.4 christos simple_object_write *dest_sobj;
325 1.1.1.4 christos simple_object_attributes *attrs;
326 1.1.1.4 christos int outfd;
327 1.1.1.4 christos
328 1.1.1.4 christos if (! sobj->functions->copy_lto_debug_sections)
329 1.1.1.4 christos {
330 1.1.1.4 christos *err = EINVAL;
331 1.1.1.4 christos return "simple_object_copy_lto_debug_sections not implemented";
332 1.1.1.4 christos }
333 1.1.1.4 christos
334 1.1.1.4 christos attrs = simple_object_fetch_attributes (sobj, &errmsg, err);
335 1.1.1.4 christos if (! attrs)
336 1.1.1.4 christos return errmsg;
337 1.1.1.4 christos dest_sobj = simple_object_start_write (attrs, NULL, &errmsg, err);
338 1.1.1.4 christos simple_object_release_attributes (attrs);
339 1.1.1.4 christos if (! dest_sobj)
340 1.1.1.4 christos return errmsg;
341 1.1.1.4 christos
342 1.1.1.5 christos errmsg = sobj->functions->copy_lto_debug_sections
343 1.1.1.5 christos (sobj, dest_sobj,
344 1.1.1.5 christos rename ? handle_lto_debug_sections_rename
345 1.1.1.5 christos : handle_lto_debug_sections_norename, err);
346 1.1.1.4 christos if (errmsg)
347 1.1.1.4 christos {
348 1.1.1.4 christos simple_object_release_write (dest_sobj);
349 1.1.1.4 christos return errmsg;
350 1.1.1.4 christos }
351 1.1.1.4 christos
352 1.1.1.4 christos outfd = creat (dest, 00777);
353 1.1.1.4 christos if (outfd == -1)
354 1.1.1.4 christos {
355 1.1.1.4 christos *err = errno;
356 1.1.1.4 christos simple_object_release_write (dest_sobj);
357 1.1.1.4 christos return "open failed";
358 1.1.1.4 christos }
359 1.1.1.4 christos
360 1.1.1.4 christos errmsg = simple_object_write_to_file (dest_sobj, outfd, err);
361 1.1.1.4 christos close (outfd);
362 1.1.1.4 christos if (errmsg)
363 1.1.1.4 christos {
364 1.1.1.4 christos simple_object_release_write (dest_sobj);
365 1.1.1.4 christos return errmsg;
366 1.1.1.4 christos }
367 1.1.1.4 christos
368 1.1.1.4 christos simple_object_release_write (dest_sobj);
369 1.1.1.4 christos return NULL;
370 1.1.1.4 christos }
371 1.1.1.4 christos
372 1.1 christos /* Fetch attributes. */
373 1.1 christos
374 1.1 christos simple_object_attributes *
375 1.1 christos simple_object_fetch_attributes (simple_object_read *sobj, const char **errmsg,
376 1.1 christos int *err)
377 1.1 christos {
378 1.1 christos void *data;
379 1.1 christos simple_object_attributes *ret;
380 1.1 christos
381 1.1 christos data = sobj->functions->fetch_attributes (sobj, errmsg, err);
382 1.1 christos if (data == NULL)
383 1.1 christos return NULL;
384 1.1 christos ret = XNEW (simple_object_attributes);
385 1.1 christos ret->functions = sobj->functions;
386 1.1 christos ret->data = data;
387 1.1 christos return ret;
388 1.1 christos }
389 1.1 christos
390 1.1 christos /* Release an simple_object_read. */
391 1.1 christos
392 1.1 christos void
393 1.1 christos simple_object_release_read (simple_object_read *sobj)
394 1.1 christos {
395 1.1 christos sobj->functions->release_read (sobj->data);
396 1.1 christos XDELETE (sobj);
397 1.1 christos }
398 1.1 christos
399 1.1.1.2 christos /* Merge attributes. */
400 1.1 christos
401 1.1 christos const char *
402 1.1.1.2 christos simple_object_attributes_merge (simple_object_attributes *to,
403 1.1.1.2 christos simple_object_attributes *from,
404 1.1.1.2 christos int *err)
405 1.1 christos {
406 1.1.1.2 christos if (to->functions != from->functions)
407 1.1 christos {
408 1.1 christos *err = 0;
409 1.1 christos return "different object file format";
410 1.1 christos }
411 1.1.1.2 christos return to->functions->attributes_merge (to->data, from->data, err);
412 1.1 christos }
413 1.1 christos
414 1.1 christos /* Release an attributes structure. */
415 1.1 christos
416 1.1 christos void
417 1.1 christos simple_object_release_attributes (simple_object_attributes *attrs)
418 1.1 christos {
419 1.1 christos attrs->functions->release_attributes (attrs->data);
420 1.1 christos XDELETE (attrs);
421 1.1 christos }
422 1.1 christos
423 1.1 christos /* Start creating an object file. */
424 1.1 christos
425 1.1 christos simple_object_write *
426 1.1 christos simple_object_start_write (simple_object_attributes *attrs,
427 1.1 christos const char *segment_name, const char **errmsg,
428 1.1 christos int *err)
429 1.1 christos {
430 1.1 christos void *data;
431 1.1 christos simple_object_write *ret;
432 1.1 christos
433 1.1 christos data = attrs->functions->start_write (attrs->data, errmsg, err);
434 1.1 christos if (data == NULL)
435 1.1 christos return NULL;
436 1.1 christos ret = XNEW (simple_object_write);
437 1.1 christos ret->functions = attrs->functions;
438 1.1.1.4 christos ret->segment_name = segment_name ? xstrdup (segment_name) : NULL;
439 1.1 christos ret->sections = NULL;
440 1.1 christos ret->last_section = NULL;
441 1.1 christos ret->data = data;
442 1.1 christos return ret;
443 1.1 christos }
444 1.1 christos
445 1.1 christos /* Start creating a section. */
446 1.1 christos
447 1.1 christos simple_object_write_section *
448 1.1 christos simple_object_write_create_section (simple_object_write *sobj, const char *name,
449 1.1 christos unsigned int align,
450 1.1 christos const char **errmsg ATTRIBUTE_UNUSED,
451 1.1 christos int *err ATTRIBUTE_UNUSED)
452 1.1 christos {
453 1.1 christos simple_object_write_section *ret;
454 1.1 christos
455 1.1 christos ret = XNEW (simple_object_write_section);
456 1.1 christos ret->next = NULL;
457 1.1 christos ret->name = xstrdup (name);
458 1.1 christos ret->align = align;
459 1.1 christos ret->buffers = NULL;
460 1.1 christos ret->last_buffer = NULL;
461 1.1 christos
462 1.1 christos if (sobj->last_section == NULL)
463 1.1 christos {
464 1.1 christos sobj->sections = ret;
465 1.1 christos sobj->last_section = ret;
466 1.1 christos }
467 1.1 christos else
468 1.1 christos {
469 1.1 christos sobj->last_section->next = ret;
470 1.1 christos sobj->last_section = ret;
471 1.1 christos }
472 1.1 christos
473 1.1 christos return ret;
474 1.1 christos }
475 1.1 christos
476 1.1 christos /* Add data to a section. */
477 1.1 christos
478 1.1 christos const char *
479 1.1 christos simple_object_write_add_data (simple_object_write *sobj ATTRIBUTE_UNUSED,
480 1.1 christos simple_object_write_section *section,
481 1.1 christos const void *buffer,
482 1.1 christos size_t size, int copy,
483 1.1 christos int *err ATTRIBUTE_UNUSED)
484 1.1 christos {
485 1.1 christos struct simple_object_write_section_buffer *wsb;
486 1.1 christos
487 1.1 christos wsb = XNEW (struct simple_object_write_section_buffer);
488 1.1 christos wsb->next = NULL;
489 1.1 christos wsb->size = size;
490 1.1 christos
491 1.1 christos if (!copy)
492 1.1 christos {
493 1.1 christos wsb->buffer = buffer;
494 1.1 christos wsb->free_buffer = NULL;
495 1.1 christos }
496 1.1 christos else
497 1.1 christos {
498 1.1 christos wsb->free_buffer = (void *) XNEWVEC (char, size);
499 1.1 christos memcpy (wsb->free_buffer, buffer, size);
500 1.1 christos wsb->buffer = wsb->free_buffer;
501 1.1 christos }
502 1.1 christos
503 1.1 christos if (section->last_buffer == NULL)
504 1.1 christos {
505 1.1 christos section->buffers = wsb;
506 1.1 christos section->last_buffer = wsb;
507 1.1 christos }
508 1.1 christos else
509 1.1 christos {
510 1.1 christos section->last_buffer->next = wsb;
511 1.1 christos section->last_buffer = wsb;
512 1.1 christos }
513 1.1 christos
514 1.1 christos return NULL;
515 1.1 christos }
516 1.1 christos
517 1.1 christos /* Write the complete object file. */
518 1.1 christos
519 1.1 christos const char *
520 1.1 christos simple_object_write_to_file (simple_object_write *sobj, int descriptor,
521 1.1 christos int *err)
522 1.1 christos {
523 1.1 christos return sobj->functions->write_to_file (sobj, descriptor, err);
524 1.1 christos }
525 1.1 christos
526 1.1 christos /* Release an simple_object_write. */
527 1.1 christos
528 1.1 christos void
529 1.1 christos simple_object_release_write (simple_object_write *sobj)
530 1.1 christos {
531 1.1 christos simple_object_write_section *section;
532 1.1 christos
533 1.1 christos free (sobj->segment_name);
534 1.1 christos
535 1.1 christos section = sobj->sections;
536 1.1 christos while (section != NULL)
537 1.1 christos {
538 1.1 christos struct simple_object_write_section_buffer *buffer;
539 1.1 christos simple_object_write_section *next_section;
540 1.1 christos
541 1.1 christos buffer = section->buffers;
542 1.1 christos while (buffer != NULL)
543 1.1 christos {
544 1.1 christos struct simple_object_write_section_buffer *next_buffer;
545 1.1 christos
546 1.1 christos if (buffer->free_buffer != NULL)
547 1.1 christos XDELETEVEC (buffer->free_buffer);
548 1.1 christos next_buffer = buffer->next;
549 1.1 christos XDELETE (buffer);
550 1.1 christos buffer = next_buffer;
551 1.1 christos }
552 1.1 christos
553 1.1 christos next_section = section->next;
554 1.1 christos free (section->name);
555 1.1 christos XDELETE (section);
556 1.1 christos section = next_section;
557 1.1 christos }
558 1.1 christos
559 1.1 christos sobj->functions->release_write (sobj->data);
560 1.1 christos XDELETE (sobj);
561 1.1 christos }
562