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