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  &simple_object_xcoff_functions
56};
57
58/* Read data from a file using the simple_object error reporting
59   conventions.  */
60
61int
62simple_object_internal_read (int descriptor, off_t offset,
63			     unsigned char *buffer, size_t size,
64			     const char **errmsg, int *err)
65{
66  if (lseek (descriptor, offset, SEEK_SET) < 0)
67    {
68      *errmsg = "lseek";
69      *err = errno;
70      return 0;
71    }
72
73  do
74    {
75      ssize_t got = read (descriptor, buffer, size);
76      if (got == 0)
77	break;
78      else if (got > 0)
79	{
80	  buffer += got;
81	  size -= got;
82	}
83      else if (errno != EINTR)
84	{
85	  *errmsg = "read";
86	  *err = errno;
87	  return 0;
88	}
89    }
90  while (size > 0);
91
92  if (size > 0)
93    {
94      *errmsg = "file too short";
95      *err = 0;
96      return 0;
97    }
98
99  return 1;
100}
101
102/* Write data to a file using the simple_object error reporting
103   conventions.  */
104
105int
106simple_object_internal_write (int descriptor, off_t offset,
107			      const unsigned char *buffer, size_t size,
108			      const char **errmsg, int *err)
109{
110  if (lseek (descriptor, offset, SEEK_SET) < 0)
111    {
112      *errmsg = "lseek";
113      *err = errno;
114      return 0;
115    }
116
117  do
118    {
119      ssize_t wrote = write (descriptor, buffer, size);
120      if (wrote == 0)
121	break;
122      else if (wrote > 0)
123	{
124	  buffer += wrote;
125	  size -= wrote;
126	}
127      else if (errno != EINTR)
128	{
129	  *errmsg = "write";
130	  *err = errno;
131	  return 0;
132	}
133    }
134  while (size > 0);
135
136  if (size > 0)
137    {
138      *errmsg = "short write";
139      *err = 0;
140      return 0;
141    }
142
143  return 1;
144}
145
146/* Open for read.  */
147
148simple_object_read *
149simple_object_start_read (int descriptor, off_t offset,
150			  const char *segment_name, const char **errmsg,
151			  int *err)
152{
153  unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN];
154  size_t len, i;
155
156  if (!simple_object_internal_read (descriptor, offset, header,
157				    SIMPLE_OBJECT_MATCH_HEADER_LEN,
158				    errmsg, err))
159    return NULL;
160
161  len = sizeof (format_functions) / sizeof (format_functions[0]);
162  for (i = 0; i < len; ++i)
163    {
164      void *data;
165
166      data = format_functions[i]->match (header, descriptor, offset,
167					 segment_name, errmsg, err);
168      if (data != NULL)
169	{
170	  simple_object_read *ret;
171
172	  ret = XNEW (simple_object_read);
173	  ret->descriptor = descriptor;
174	  ret->offset = offset;
175	  ret->functions = format_functions[i];
176	  ret->data = data;
177	  return ret;
178	}
179    }
180
181  *errmsg = "file not recognized";
182  *err = 0;
183  return NULL;
184}
185
186/* Find all sections.  */
187
188const char *
189simple_object_find_sections (simple_object_read *sobj,
190			     int (*pfn) (void *, const char *, off_t, off_t),
191			     void *data,
192			     int *err)
193{
194  return sobj->functions->find_sections (sobj, pfn, data, err);
195}
196
197/* Internal data passed to find_one_section.  */
198
199struct find_one_section_data
200{
201  /* The section we are looking for.  */
202  const char *name;
203  /* Where to store the section offset.  */
204  off_t *offset;
205  /* Where to store the section length.  */
206  off_t *length;
207  /* Set if the name is found.  */
208  int found;
209};
210
211/* Internal function passed to find_sections.  */
212
213static int
214find_one_section (void *data, const char *name, off_t offset, off_t length)
215{
216  struct find_one_section_data *fosd = (struct find_one_section_data *) data;
217
218  if (strcmp (name, fosd->name) != 0)
219    return 1;
220
221  *fosd->offset = offset;
222  *fosd->length = length;
223  fosd->found = 1;
224
225  /* Stop iteration.  */
226  return 0;
227}
228
229/* Find a section.  */
230
231int
232simple_object_find_section (simple_object_read *sobj, const char *name,
233			    off_t *offset, off_t *length,
234			    const char **errmsg, int *err)
235{
236  struct find_one_section_data fosd;
237
238  fosd.name = name;
239  fosd.offset = offset;
240  fosd.length = length;
241  fosd.found = 0;
242
243  *errmsg = simple_object_find_sections (sobj, find_one_section,
244					 (void *) &fosd, err);
245  if (*errmsg != NULL)
246    return 0;
247  if (!fosd.found)
248    return 0;
249  return 1;
250}
251
252/* Fetch attributes.  */
253
254simple_object_attributes *
255simple_object_fetch_attributes (simple_object_read *sobj, const char **errmsg,
256				int *err)
257{
258  void *data;
259  simple_object_attributes *ret;
260
261  data = sobj->functions->fetch_attributes (sobj, errmsg, err);
262  if (data == NULL)
263    return NULL;
264  ret = XNEW (simple_object_attributes);
265  ret->functions = sobj->functions;
266  ret->data = data;
267  return ret;
268}
269
270/* Release an simple_object_read.  */
271
272void
273simple_object_release_read (simple_object_read *sobj)
274{
275  sobj->functions->release_read (sobj->data);
276  XDELETE (sobj);
277}
278
279/* Merge attributes.  */
280
281const char *
282simple_object_attributes_merge (simple_object_attributes *to,
283				simple_object_attributes *from,
284				int *err)
285{
286  if (to->functions != from->functions)
287    {
288      *err = 0;
289      return "different object file format";
290    }
291  return to->functions->attributes_merge (to->data, from->data, err);
292}
293
294/* Release an attributes structure.  */
295
296void
297simple_object_release_attributes (simple_object_attributes *attrs)
298{
299  attrs->functions->release_attributes (attrs->data);
300  XDELETE (attrs);
301}
302
303/* Start creating an object file.  */
304
305simple_object_write *
306simple_object_start_write (simple_object_attributes *attrs,
307			   const char *segment_name, const char **errmsg,
308			   int *err)
309{
310  void *data;
311  simple_object_write *ret;
312
313  data = attrs->functions->start_write (attrs->data, errmsg, err);
314  if (data == NULL)
315    return NULL;
316  ret = XNEW (simple_object_write);
317  ret->functions = attrs->functions;
318  ret->segment_name = xstrdup (segment_name);
319  ret->sections = NULL;
320  ret->last_section = NULL;
321  ret->data = data;
322  return ret;
323}
324
325/* Start creating a section.  */
326
327simple_object_write_section *
328simple_object_write_create_section (simple_object_write *sobj, const char *name,
329				    unsigned int align,
330				    const char **errmsg ATTRIBUTE_UNUSED,
331				    int *err ATTRIBUTE_UNUSED)
332{
333  simple_object_write_section *ret;
334
335  ret = XNEW (simple_object_write_section);
336  ret->next = NULL;
337  ret->name = xstrdup (name);
338  ret->align = align;
339  ret->buffers = NULL;
340  ret->last_buffer = NULL;
341
342  if (sobj->last_section == NULL)
343    {
344      sobj->sections = ret;
345      sobj->last_section = ret;
346    }
347  else
348    {
349      sobj->last_section->next = ret;
350      sobj->last_section = ret;
351    }
352
353  return ret;
354}
355
356/* Add data to a section.  */
357
358const char *
359simple_object_write_add_data (simple_object_write *sobj ATTRIBUTE_UNUSED,
360			      simple_object_write_section *section,
361			      const void *buffer,
362			      size_t size, int copy,
363			      int *err ATTRIBUTE_UNUSED)
364{
365  struct simple_object_write_section_buffer *wsb;
366
367  wsb = XNEW (struct simple_object_write_section_buffer);
368  wsb->next = NULL;
369  wsb->size = size;
370
371  if (!copy)
372    {
373      wsb->buffer = buffer;
374      wsb->free_buffer = NULL;
375    }
376  else
377    {
378      wsb->free_buffer = (void *) XNEWVEC (char, size);
379      memcpy (wsb->free_buffer, buffer, size);
380      wsb->buffer = wsb->free_buffer;
381    }
382
383  if (section->last_buffer == NULL)
384    {
385      section->buffers = wsb;
386      section->last_buffer = wsb;
387    }
388  else
389    {
390      section->last_buffer->next = wsb;
391      section->last_buffer = wsb;
392    }
393
394  return NULL;
395}
396
397/* Write the complete object file.  */
398
399const char *
400simple_object_write_to_file (simple_object_write *sobj, int descriptor,
401			     int *err)
402{
403  return sobj->functions->write_to_file (sobj, descriptor, err);
404}
405
406/* Release an simple_object_write.  */
407
408void
409simple_object_release_write (simple_object_write *sobj)
410{
411  simple_object_write_section *section;
412
413  free (sobj->segment_name);
414
415  section = sobj->sections;
416  while (section != NULL)
417    {
418      struct simple_object_write_section_buffer *buffer;
419      simple_object_write_section *next_section;
420
421      buffer = section->buffers;
422      while (buffer != NULL)
423	{
424	  struct simple_object_write_section_buffer *next_buffer;
425
426	  if (buffer->free_buffer != NULL)
427	    XDELETEVEC (buffer->free_buffer);
428	  next_buffer = buffer->next;
429	  XDELETE (buffer);
430	  buffer = next_buffer;
431	}
432
433      next_section = section->next;
434      free (section->name);
435      XDELETE (section);
436      section = next_section;
437    }
438
439  sobj->functions->release_write (sobj->data);
440  XDELETE (sobj);
441}
442