simple-object.c revision 1.1.1.6 1 1.1 christos /* simple-object.c -- simple routines to read and write object files.
2 1.1.1.6 christos Copyright (C) 2010-2020 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.5 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.1.6 christos #ifndef O_BINARY
48 1.1.1.6 christos #define O_BINARY 0
49 1.1.1.6 christos #endif
50 1.1.1.6 christos
51 1.1 christos #include "simple-object-common.h"
52 1.1 christos
53 1.1 christos /* The known object file formats. */
54 1.1 christos
55 1.1 christos static const struct simple_object_functions * const format_functions[] =
56 1.1 christos {
57 1.1 christos &simple_object_elf_functions,
58 1.1 christos &simple_object_mach_o_functions,
59 1.1.1.2 christos &simple_object_coff_functions,
60 1.1.1.2 christos &simple_object_xcoff_functions
61 1.1 christos };
62 1.1 christos
63 1.1 christos /* Read data from a file using the simple_object error reporting
64 1.1 christos conventions. */
65 1.1 christos
66 1.1 christos int
67 1.1 christos simple_object_internal_read (int descriptor, off_t offset,
68 1.1 christos unsigned char *buffer, size_t size,
69 1.1 christos const char **errmsg, int *err)
70 1.1 christos {
71 1.1 christos if (lseek (descriptor, offset, SEEK_SET) < 0)
72 1.1 christos {
73 1.1 christos *errmsg = "lseek";
74 1.1 christos *err = errno;
75 1.1 christos return 0;
76 1.1 christos }
77 1.1 christos
78 1.1.1.3 christos do
79 1.1 christos {
80 1.1.1.3 christos ssize_t got = read (descriptor, buffer, size);
81 1.1.1.3 christos if (got == 0)
82 1.1.1.3 christos break;
83 1.1.1.3 christos else if (got > 0)
84 1.1.1.3 christos {
85 1.1.1.3 christos buffer += got;
86 1.1.1.3 christos size -= got;
87 1.1.1.3 christos }
88 1.1.1.3 christos else if (errno != EINTR)
89 1.1.1.3 christos {
90 1.1.1.3 christos *errmsg = "read";
91 1.1.1.3 christos *err = errno;
92 1.1.1.3 christos return 0;
93 1.1.1.3 christos }
94 1.1 christos }
95 1.1.1.3 christos while (size > 0);
96 1.1 christos
97 1.1.1.3 christos if (size > 0)
98 1.1 christos {
99 1.1 christos *errmsg = "file too short";
100 1.1 christos *err = 0;
101 1.1 christos return 0;
102 1.1 christos }
103 1.1 christos
104 1.1 christos return 1;
105 1.1 christos }
106 1.1 christos
107 1.1 christos /* Write data to a file using the simple_object error reporting
108 1.1 christos conventions. */
109 1.1 christos
110 1.1 christos int
111 1.1 christos simple_object_internal_write (int descriptor, off_t offset,
112 1.1 christos const unsigned char *buffer, size_t size,
113 1.1 christos const char **errmsg, int *err)
114 1.1 christos {
115 1.1 christos if (lseek (descriptor, offset, SEEK_SET) < 0)
116 1.1 christos {
117 1.1 christos *errmsg = "lseek";
118 1.1 christos *err = errno;
119 1.1 christos return 0;
120 1.1 christos }
121 1.1 christos
122 1.1.1.3 christos do
123 1.1 christos {
124 1.1.1.3 christos ssize_t wrote = write (descriptor, buffer, size);
125 1.1.1.3 christos if (wrote == 0)
126 1.1.1.3 christos break;
127 1.1.1.3 christos else if (wrote > 0)
128 1.1.1.3 christos {
129 1.1.1.3 christos buffer += wrote;
130 1.1.1.3 christos size -= wrote;
131 1.1.1.3 christos }
132 1.1.1.3 christos else if (errno != EINTR)
133 1.1.1.3 christos {
134 1.1.1.3 christos *errmsg = "write";
135 1.1.1.3 christos *err = errno;
136 1.1.1.3 christos return 0;
137 1.1.1.3 christos }
138 1.1 christos }
139 1.1.1.3 christos while (size > 0);
140 1.1 christos
141 1.1.1.3 christos if (size > 0)
142 1.1 christos {
143 1.1 christos *errmsg = "short write";
144 1.1 christos *err = 0;
145 1.1 christos return 0;
146 1.1 christos }
147 1.1 christos
148 1.1 christos return 1;
149 1.1 christos }
150 1.1 christos
151 1.1 christos /* Open for read. */
152 1.1 christos
153 1.1 christos simple_object_read *
154 1.1 christos simple_object_start_read (int descriptor, off_t offset,
155 1.1 christos const char *segment_name, const char **errmsg,
156 1.1 christos int *err)
157 1.1 christos {
158 1.1 christos unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN];
159 1.1 christos size_t len, i;
160 1.1 christos
161 1.1 christos if (!simple_object_internal_read (descriptor, offset, header,
162 1.1 christos SIMPLE_OBJECT_MATCH_HEADER_LEN,
163 1.1 christos errmsg, err))
164 1.1 christos return NULL;
165 1.1 christos
166 1.1 christos len = sizeof (format_functions) / sizeof (format_functions[0]);
167 1.1 christos for (i = 0; i < len; ++i)
168 1.1 christos {
169 1.1 christos void *data;
170 1.1 christos
171 1.1 christos data = format_functions[i]->match (header, descriptor, offset,
172 1.1 christos segment_name, errmsg, err);
173 1.1 christos if (data != NULL)
174 1.1 christos {
175 1.1 christos simple_object_read *ret;
176 1.1 christos
177 1.1 christos ret = XNEW (simple_object_read);
178 1.1 christos ret->descriptor = descriptor;
179 1.1 christos ret->offset = offset;
180 1.1 christos ret->functions = format_functions[i];
181 1.1 christos ret->data = data;
182 1.1 christos return ret;
183 1.1 christos }
184 1.1 christos }
185 1.1 christos
186 1.1 christos *errmsg = "file not recognized";
187 1.1 christos *err = 0;
188 1.1 christos return NULL;
189 1.1 christos }
190 1.1 christos
191 1.1 christos /* Find all sections. */
192 1.1 christos
193 1.1 christos const char *
194 1.1 christos simple_object_find_sections (simple_object_read *sobj,
195 1.1 christos int (*pfn) (void *, const char *, off_t, off_t),
196 1.1 christos void *data,
197 1.1 christos int *err)
198 1.1 christos {
199 1.1 christos return sobj->functions->find_sections (sobj, pfn, data, err);
200 1.1 christos }
201 1.1 christos
202 1.1 christos /* Internal data passed to find_one_section. */
203 1.1 christos
204 1.1 christos struct find_one_section_data
205 1.1 christos {
206 1.1 christos /* The section we are looking for. */
207 1.1 christos const char *name;
208 1.1 christos /* Where to store the section offset. */
209 1.1 christos off_t *offset;
210 1.1 christos /* Where to store the section length. */
211 1.1 christos off_t *length;
212 1.1 christos /* Set if the name is found. */
213 1.1 christos int found;
214 1.1 christos };
215 1.1 christos
216 1.1 christos /* Internal function passed to find_sections. */
217 1.1 christos
218 1.1 christos static int
219 1.1 christos find_one_section (void *data, const char *name, off_t offset, off_t length)
220 1.1 christos {
221 1.1 christos struct find_one_section_data *fosd = (struct find_one_section_data *) data;
222 1.1 christos
223 1.1 christos if (strcmp (name, fosd->name) != 0)
224 1.1 christos return 1;
225 1.1 christos
226 1.1 christos *fosd->offset = offset;
227 1.1 christos *fosd->length = length;
228 1.1 christos fosd->found = 1;
229 1.1 christos
230 1.1 christos /* Stop iteration. */
231 1.1 christos return 0;
232 1.1 christos }
233 1.1 christos
234 1.1 christos /* Find a section. */
235 1.1 christos
236 1.1 christos int
237 1.1 christos simple_object_find_section (simple_object_read *sobj, const char *name,
238 1.1 christos off_t *offset, off_t *length,
239 1.1 christos const char **errmsg, int *err)
240 1.1 christos {
241 1.1 christos struct find_one_section_data fosd;
242 1.1 christos
243 1.1 christos fosd.name = name;
244 1.1 christos fosd.offset = offset;
245 1.1 christos fosd.length = length;
246 1.1 christos fosd.found = 0;
247 1.1 christos
248 1.1 christos *errmsg = simple_object_find_sections (sobj, find_one_section,
249 1.1 christos (void *) &fosd, err);
250 1.1 christos if (*errmsg != NULL)
251 1.1 christos return 0;
252 1.1 christos if (!fosd.found)
253 1.1 christos return 0;
254 1.1 christos return 1;
255 1.1 christos }
256 1.1 christos
257 1.1.1.5 christos /* Callback to identify and rename LTO debug sections by name.
258 1.1.1.5 christos Returns non-NULL if NAME is a LTO debug section, NULL if not.
259 1.1.1.5 christos If RENAME is true it will rename LTO debug sections to non-LTO
260 1.1.1.5 christos ones. */
261 1.1.1.5 christos
262 1.1.1.5 christos static char *
263 1.1.1.5 christos handle_lto_debug_sections (const char *name, int rename)
264 1.1.1.5 christos {
265 1.1.1.5 christos char *newname = rename ? XCNEWVEC (char, strlen (name) + 1)
266 1.1.1.5 christos : xstrdup (name);
267 1.1.1.5 christos
268 1.1.1.5 christos /* ??? So we can't use .gnu.lto_ prefixed sections as the assembler
269 1.1.1.5 christos complains about bogus section flags. Which means we need to arrange
270 1.1.1.5 christos for that to be fixed or .gnu.debuglto_ marked as SHF_EXCLUDE (to make
271 1.1.1.5 christos fat lto object tooling work for the fat part). */
272 1.1.1.5 christos /* Also include corresponding reloc sections. */
273 1.1.1.5 christos if (strncmp (name, ".rela", sizeof (".rela") - 1) == 0)
274 1.1.1.5 christos {
275 1.1.1.5 christos if (rename)
276 1.1.1.5 christos strncpy (newname, name, sizeof (".rela") - 1);
277 1.1.1.5 christos name += sizeof (".rela") - 1;
278 1.1.1.5 christos }
279 1.1.1.5 christos else if (strncmp (name, ".rel", sizeof (".rel") - 1) == 0)
280 1.1.1.5 christos {
281 1.1.1.5 christos if (rename)
282 1.1.1.5 christos strncpy (newname, name, sizeof (".rel") - 1);
283 1.1.1.5 christos name += sizeof (".rel") - 1;
284 1.1.1.5 christos }
285 1.1.1.5 christos /* ??? For now this handles both .gnu.lto_ and .gnu.debuglto_ prefixed
286 1.1.1.5 christos sections. */
287 1.1.1.5 christos /* Copy LTO debug sections and rename them to their non-LTO name. */
288 1.1.1.5 christos if (strncmp (name, ".gnu.debuglto_", sizeof (".gnu.debuglto_") - 1) == 0)
289 1.1.1.5 christos return rename ? strcat (newname, name + sizeof (".gnu.debuglto_") - 1) : newname;
290 1.1.1.5 christos else if (strncmp (name, ".gnu.lto_.debug_",
291 1.1.1.5 christos sizeof (".gnu.lto_.debug_") -1) == 0)
292 1.1.1.5 christos return rename ? strcat (newname, name + sizeof (".gnu.lto_") - 1) : newname;
293 1.1.1.5 christos /* Copy over .note.GNU-stack section under the same name if present. */
294 1.1.1.5 christos else if (strcmp (name, ".note.GNU-stack") == 0)
295 1.1.1.5 christos return strcpy (newname, name);
296 1.1.1.6 christos /* Copy over .note.gnu.property section under the same name if present. */
297 1.1.1.6 christos else if (strcmp (name, ".note.gnu.property") == 0)
298 1.1.1.6 christos return strcpy (newname, name);
299 1.1.1.5 christos /* Copy over .comment section under the same name if present. Solaris
300 1.1.1.5 christos ld uses them to relax its checking of ELF gABI access rules for
301 1.1.1.5 christos COMDAT sections in objects produced by GCC. */
302 1.1.1.5 christos else if (strcmp (name, ".comment") == 0)
303 1.1.1.5 christos return strcpy (newname, name);
304 1.1.1.6 christos /* Copy over .GCC.command.line section under the same name if present. */
305 1.1.1.6 christos else if (strcmp (name, ".GCC.command.line") == 0)
306 1.1.1.6 christos return strcpy (newname, name);
307 1.1.1.5 christos free (newname);
308 1.1.1.5 christos return NULL;
309 1.1.1.5 christos }
310 1.1.1.5 christos
311 1.1.1.5 christos /* Wrapper for handle_lto_debug_sections. */
312 1.1.1.5 christos
313 1.1.1.5 christos static char *
314 1.1.1.5 christos handle_lto_debug_sections_rename (const char *name)
315 1.1.1.5 christos {
316 1.1.1.5 christos return handle_lto_debug_sections (name, 1);
317 1.1.1.5 christos }
318 1.1.1.5 christos
319 1.1.1.5 christos /* Wrapper for handle_lto_debug_sections. */
320 1.1.1.5 christos
321 1.1.1.5 christos static char *
322 1.1.1.5 christos handle_lto_debug_sections_norename (const char *name)
323 1.1.1.5 christos {
324 1.1.1.5 christos return handle_lto_debug_sections (name, 0);
325 1.1.1.5 christos }
326 1.1.1.5 christos
327 1.1.1.5 christos /* Copy LTO debug sections. */
328 1.1.1.5 christos
329 1.1.1.5 christos const char *
330 1.1.1.5 christos simple_object_copy_lto_debug_sections (simple_object_read *sobj,
331 1.1.1.5 christos const char *dest, int *err, int rename)
332 1.1.1.5 christos {
333 1.1.1.5 christos const char *errmsg;
334 1.1.1.5 christos simple_object_write *dest_sobj;
335 1.1.1.5 christos simple_object_attributes *attrs;
336 1.1.1.5 christos int outfd;
337 1.1.1.5 christos
338 1.1.1.5 christos if (! sobj->functions->copy_lto_debug_sections)
339 1.1.1.5 christos {
340 1.1.1.5 christos *err = EINVAL;
341 1.1.1.5 christos return "simple_object_copy_lto_debug_sections not implemented";
342 1.1.1.5 christos }
343 1.1.1.5 christos
344 1.1.1.5 christos attrs = simple_object_fetch_attributes (sobj, &errmsg, err);
345 1.1.1.5 christos if (! attrs)
346 1.1.1.5 christos return errmsg;
347 1.1.1.5 christos dest_sobj = simple_object_start_write (attrs, NULL, &errmsg, err);
348 1.1.1.5 christos simple_object_release_attributes (attrs);
349 1.1.1.5 christos if (! dest_sobj)
350 1.1.1.5 christos return errmsg;
351 1.1.1.5 christos
352 1.1.1.5 christos errmsg = sobj->functions->copy_lto_debug_sections
353 1.1.1.5 christos (sobj, dest_sobj,
354 1.1.1.5 christos rename ? handle_lto_debug_sections_rename
355 1.1.1.5 christos : handle_lto_debug_sections_norename, err);
356 1.1.1.5 christos if (errmsg)
357 1.1.1.5 christos {
358 1.1.1.5 christos simple_object_release_write (dest_sobj);
359 1.1.1.5 christos return errmsg;
360 1.1.1.5 christos }
361 1.1.1.5 christos
362 1.1.1.6 christos outfd = open (dest, O_CREAT|O_WRONLY|O_TRUNC|O_BINARY, 00777);
363 1.1.1.5 christos if (outfd == -1)
364 1.1.1.5 christos {
365 1.1.1.5 christos *err = errno;
366 1.1.1.5 christos simple_object_release_write (dest_sobj);
367 1.1.1.5 christos return "open failed";
368 1.1.1.5 christos }
369 1.1.1.5 christos
370 1.1.1.5 christos errmsg = simple_object_write_to_file (dest_sobj, outfd, err);
371 1.1.1.5 christos close (outfd);
372 1.1.1.5 christos if (errmsg)
373 1.1.1.5 christos {
374 1.1.1.5 christos simple_object_release_write (dest_sobj);
375 1.1.1.5 christos return errmsg;
376 1.1.1.5 christos }
377 1.1.1.5 christos
378 1.1.1.5 christos simple_object_release_write (dest_sobj);
379 1.1.1.5 christos return NULL;
380 1.1.1.5 christos }
381 1.1.1.5 christos
382 1.1 christos /* Fetch attributes. */
383 1.1 christos
384 1.1 christos simple_object_attributes *
385 1.1 christos simple_object_fetch_attributes (simple_object_read *sobj, const char **errmsg,
386 1.1 christos int *err)
387 1.1 christos {
388 1.1 christos void *data;
389 1.1 christos simple_object_attributes *ret;
390 1.1 christos
391 1.1 christos data = sobj->functions->fetch_attributes (sobj, errmsg, err);
392 1.1 christos if (data == NULL)
393 1.1 christos return NULL;
394 1.1 christos ret = XNEW (simple_object_attributes);
395 1.1 christos ret->functions = sobj->functions;
396 1.1 christos ret->data = data;
397 1.1 christos return ret;
398 1.1 christos }
399 1.1 christos
400 1.1 christos /* Release an simple_object_read. */
401 1.1 christos
402 1.1 christos void
403 1.1 christos simple_object_release_read (simple_object_read *sobj)
404 1.1 christos {
405 1.1 christos sobj->functions->release_read (sobj->data);
406 1.1 christos XDELETE (sobj);
407 1.1 christos }
408 1.1 christos
409 1.1 christos /* Merge attributes. */
410 1.1 christos
411 1.1 christos const char *
412 1.1 christos simple_object_attributes_merge (simple_object_attributes *to,
413 1.1 christos simple_object_attributes *from,
414 1.1 christos int *err)
415 1.1 christos {
416 1.1 christos if (to->functions != from->functions)
417 1.1 christos {
418 1.1 christos *err = 0;
419 1.1 christos return "different object file format";
420 1.1 christos }
421 1.1 christos return to->functions->attributes_merge (to->data, from->data, err);
422 1.1 christos }
423 1.1 christos
424 1.1 christos /* Release an attributes structure. */
425 1.1 christos
426 1.1 christos void
427 1.1 christos simple_object_release_attributes (simple_object_attributes *attrs)
428 1.1 christos {
429 1.1 christos attrs->functions->release_attributes (attrs->data);
430 1.1 christos XDELETE (attrs);
431 1.1 christos }
432 1.1 christos
433 1.1 christos /* Start creating an object file. */
434 1.1 christos
435 1.1 christos simple_object_write *
436 1.1 christos simple_object_start_write (simple_object_attributes *attrs,
437 1.1 christos const char *segment_name, const char **errmsg,
438 1.1 christos int *err)
439 1.1 christos {
440 1.1 christos void *data;
441 1.1 christos simple_object_write *ret;
442 1.1 christos
443 1.1 christos data = attrs->functions->start_write (attrs->data, errmsg, err);
444 1.1 christos if (data == NULL)
445 1.1 christos return NULL;
446 1.1 christos ret = XNEW (simple_object_write);
447 1.1 christos ret->functions = attrs->functions;
448 1.1.1.5 christos ret->segment_name = segment_name ? xstrdup (segment_name) : NULL;
449 1.1 christos ret->sections = NULL;
450 1.1 christos ret->last_section = NULL;
451 1.1 christos ret->data = data;
452 1.1 christos return ret;
453 1.1 christos }
454 1.1 christos
455 1.1 christos /* Start creating a section. */
456 1.1 christos
457 1.1 christos simple_object_write_section *
458 1.1 christos simple_object_write_create_section (simple_object_write *sobj, const char *name,
459 1.1 christos unsigned int align,
460 1.1 christos const char **errmsg ATTRIBUTE_UNUSED,
461 1.1 christos int *err ATTRIBUTE_UNUSED)
462 1.1 christos {
463 1.1 christos simple_object_write_section *ret;
464 1.1 christos
465 1.1 christos ret = XNEW (simple_object_write_section);
466 1.1 christos ret->next = NULL;
467 1.1 christos ret->name = xstrdup (name);
468 1.1 christos ret->align = align;
469 1.1 christos ret->buffers = NULL;
470 1.1 christos ret->last_buffer = NULL;
471 1.1 christos
472 1.1 christos if (sobj->last_section == NULL)
473 1.1 christos {
474 1.1 christos sobj->sections = ret;
475 1.1 christos sobj->last_section = ret;
476 1.1 christos }
477 1.1 christos else
478 1.1 christos {
479 1.1 christos sobj->last_section->next = ret;
480 1.1 christos sobj->last_section = ret;
481 1.1 christos }
482 1.1 christos
483 1.1 christos return ret;
484 1.1 christos }
485 1.1 christos
486 1.1 christos /* Add data to a section. */
487 1.1 christos
488 1.1 christos const char *
489 1.1 christos simple_object_write_add_data (simple_object_write *sobj ATTRIBUTE_UNUSED,
490 1.1 christos simple_object_write_section *section,
491 1.1 christos const void *buffer,
492 1.1 christos size_t size, int copy,
493 1.1 christos int *err ATTRIBUTE_UNUSED)
494 1.1 christos {
495 1.1 christos struct simple_object_write_section_buffer *wsb;
496 1.1 christos
497 1.1 christos wsb = XNEW (struct simple_object_write_section_buffer);
498 1.1 christos wsb->next = NULL;
499 1.1 christos wsb->size = size;
500 1.1 christos
501 1.1 christos if (!copy)
502 1.1 christos {
503 1.1 christos wsb->buffer = buffer;
504 1.1 christos wsb->free_buffer = NULL;
505 1.1 christos }
506 1.1 christos else
507 1.1 christos {
508 1.1 christos wsb->free_buffer = (void *) XNEWVEC (char, size);
509 1.1 christos memcpy (wsb->free_buffer, buffer, size);
510 1.1 christos wsb->buffer = wsb->free_buffer;
511 1.1 christos }
512 1.1 christos
513 1.1 christos if (section->last_buffer == NULL)
514 1.1 christos {
515 1.1 christos section->buffers = wsb;
516 1.1 christos section->last_buffer = wsb;
517 1.1 christos }
518 1.1 christos else
519 1.1 christos {
520 1.1 christos section->last_buffer->next = wsb;
521 1.1 christos section->last_buffer = wsb;
522 1.1 christos }
523 1.1 christos
524 1.1 christos return NULL;
525 1.1 christos }
526 1.1 christos
527 1.1 christos /* Write the complete object file. */
528 1.1 christos
529 1.1 christos const char *
530 1.1 christos simple_object_write_to_file (simple_object_write *sobj, int descriptor,
531 1.1 christos int *err)
532 1.1 christos {
533 1.1 christos return sobj->functions->write_to_file (sobj, descriptor, err);
534 1.1 christos }
535 1.1 christos
536 1.1 christos /* Release an simple_object_write. */
537 1.1 christos
538 1.1 christos void
539 1.1 christos simple_object_release_write (simple_object_write *sobj)
540 1.1 christos {
541 1.1 christos simple_object_write_section *section;
542 1.1 christos
543 1.1 christos free (sobj->segment_name);
544 1.1 christos
545 1.1 christos section = sobj->sections;
546 1.1 christos while (section != NULL)
547 1.1 christos {
548 1.1 christos struct simple_object_write_section_buffer *buffer;
549 1.1 christos simple_object_write_section *next_section;
550 1.1 christos
551 1.1 christos buffer = section->buffers;
552 1.1 christos while (buffer != NULL)
553 1.1 christos {
554 1.1 christos struct simple_object_write_section_buffer *next_buffer;
555 1.1 christos
556 1.1 christos if (buffer->free_buffer != NULL)
557 1.1 christos XDELETEVEC (buffer->free_buffer);
558 1.1 christos next_buffer = buffer->next;
559 1.1 christos XDELETE (buffer);
560 1.1 christos buffer = next_buffer;
561 1.1 christos }
562 1.1 christos
563 1.1 christos next_section = section->next;
564 1.1 christos free (section->name);
565 1.1 christos XDELETE (section);
566 1.1 christos section = next_section;
567 1.1 christos }
568 1.1 christos
569 1.1 christos sobj->functions->release_write (sobj->data);
570 1.1 christos XDELETE (sobj);
571 1.1 christos }
572