This commit was generated by cvs2svn to track changes on a CVS vendor
[external/binutils.git] / bfd / ppcboot.c
1 /* BFD back-end for PPCbug boot records.
2    Copyright 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
3    Written by Michael Meissner, Cygnus Support, <meissner@cygnus.com>
4
5 This file is part of BFD, the Binary File Descriptor library.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 /* This is a BFD backend which may be used to write PowerPCBug boot objects.
22    It may only be used for output, not input.  The intention is that this may
23    be used as an output format for objcopy in order to generate raw binary
24    data.
25
26    This is very simple.  The only complication is that the real data
27    will start at some address X, and in some cases we will not want to
28    include X zeroes just to get to that point.  Since the start
29    address is not meaningful for this object file format, we use it
30    instead to indicate the number of zeroes to skip at the start of
31    the file.  objcopy cooperates by specially setting the start
32    address to zero by default.  */
33
34 #include <ctype.h>
35
36 #include "bfd.h"
37 #include "sysdep.h"
38 #include "libbfd.h"
39
40 /* PPCbug location structure */
41 typedef struct ppcboot_location {
42   bfd_byte      ind;
43   bfd_byte      head;
44   bfd_byte      sector;
45   bfd_byte      cylinder;
46 } ppcboot_location_t;
47
48 /* PPCbug partition table layout */
49 typedef struct ppcboot_partition {
50   ppcboot_location_t    partition_begin;        /* partition begin */
51   ppcboot_location_t    partition_end;          /* partition end */
52   bfd_byte              sector_begin[4];        /* 32-bit start RBA (zero-based), little endian */
53   bfd_byte              sector_length[4];       /* 32-bit RBA count (one-based), little endian */
54 } ppcboot_partition_t;
55
56 /* PPCbug boot layout.  */
57 typedef struct ppcboot_hdr {
58   bfd_byte              pc_compatibility[446];  /* x86 instruction field */
59   ppcboot_partition_t   partition[4];           /* partition information */
60   bfd_byte              signature[2];           /* 0x55 and 0xaa */
61   bfd_byte              entry_offset[4];        /* entry point offset, little endian */
62   bfd_byte              length[4];              /* load image length, little endian */
63   bfd_byte              flags;                  /* flag field */
64   bfd_byte              os_id;                  /* OS_ID */
65   char                  partition_name[32];     /* partition name */
66   bfd_byte              reserved1[470];         /* reserved */
67 }
68 #ifdef __GNUC__
69   __attribute__ ((packed))
70 #endif
71 ppcboot_hdr_t;
72
73 /* Signature bytes for last 2 bytes of the 512 byte record */
74 #define SIGNATURE0 0x55
75 #define SIGNATURE1 0xaa
76
77 /* PowerPC boot type */
78 #define PPC_IND 0x41
79
80 /* Information needed for ppcboot header */
81 typedef struct ppcboot_data {
82   ppcboot_hdr_t header;                         /* raw header */
83   asection *sec;                                /* single section */
84 } ppcboot_data_t;
85
86 /* Any bfd we create by reading a ppcboot file has three symbols:
87    a start symbol, an end symbol, and an absolute length symbol.  */
88 #define PPCBOOT_SYMS 3
89
90 static boolean ppcboot_mkobject PARAMS ((bfd *));
91 static const bfd_target *ppcboot_object_p PARAMS ((bfd *));
92 static boolean ppcboot_set_arch_mach
93   PARAMS ((bfd *, enum bfd_architecture, unsigned long));
94 static boolean ppcboot_get_section_contents
95   PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type));
96 static long ppcboot_get_symtab_upper_bound PARAMS ((bfd *));
97 static char *mangle_name PARAMS ((bfd *, char *));
98 static long ppcboot_get_symtab PARAMS ((bfd *, asymbol **));
99 static asymbol *ppcboot_make_empty_symbol PARAMS ((bfd *));
100 static void ppcboot_get_symbol_info PARAMS ((bfd *, asymbol *, symbol_info *));
101 static boolean ppcboot_set_section_contents
102   PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type));
103 static int ppcboot_sizeof_headers PARAMS ((bfd *, boolean));
104 static boolean ppcboot_bfd_print_private_bfd_data PARAMS ((bfd *, PTR));
105
106 #define ppcboot_set_tdata(abfd, ptr) ((abfd)->tdata.any = (PTR) (ptr))
107 #define ppcboot_get_tdata(abfd) ((ppcboot_data_t *) ((abfd)->tdata.any))
108 \f
109 /* Create a ppcboot object.  Invoked via bfd_set_format.  */
110
111 static boolean
112 ppcboot_mkobject (abfd)
113      bfd *abfd;
114 {
115   if (!ppcboot_get_tdata (abfd))
116     ppcboot_set_tdata (abfd, bfd_zalloc (abfd, sizeof (ppcboot_data_t)));
117
118   return true;
119 }
120
121 \f
122 /* Set the architecture to PowerPC */
123 static boolean
124 ppcboot_set_arch_mach (abfd, arch, machine)
125      bfd *abfd;
126      enum bfd_architecture arch;
127      unsigned long machine;
128 {
129   if (arch == bfd_arch_unknown)
130     arch = bfd_arch_powerpc;
131
132   else if (arch != bfd_arch_powerpc)
133     return false;
134
135   return bfd_default_set_arch_mach (abfd, arch, machine);
136 }
137
138 \f
139 /* Any file may be considered to be a ppcboot file, provided the target
140    was not defaulted.  That is, it must be explicitly specified as
141    being ppcboot.  */
142
143 static const bfd_target *
144 ppcboot_object_p (abfd)
145      bfd *abfd;
146 {
147   struct stat statbuf;
148   asection *sec;
149   ppcboot_hdr_t hdr;
150   size_t i;
151   ppcboot_data_t *tdata;
152
153   BFD_ASSERT (sizeof (ppcboot_hdr_t) == 1024);
154
155   if (abfd->target_defaulted)
156     {
157       bfd_set_error (bfd_error_wrong_format);
158       return NULL;
159     }
160
161   /* Find the file size.  */
162   if (bfd_stat (abfd, &statbuf) < 0)
163     {
164       bfd_set_error (bfd_error_system_call);
165       return NULL;
166     }
167
168   if ((size_t) statbuf.st_size < sizeof (ppcboot_hdr_t))
169     {
170       bfd_set_error (bfd_error_wrong_format);
171       return NULL;
172     }
173
174   if (bfd_read ((PTR) &hdr, sizeof (hdr), 1, abfd) != sizeof (hdr))
175     {
176       if (bfd_get_error () != bfd_error_system_call)
177         bfd_set_error (bfd_error_wrong_format);
178
179       return NULL;
180     }
181
182   /* Now do some basic checks.  */
183   for (i = 0; i < sizeof (hdr.pc_compatibility); i++)
184     if (hdr.pc_compatibility[i])
185       {
186         bfd_set_error (bfd_error_wrong_format);
187         return NULL;
188       }
189
190   if (hdr.signature[0] != SIGNATURE0 || hdr.signature[1] != SIGNATURE1)
191     {
192       bfd_set_error (bfd_error_wrong_format);
193       return NULL;
194     }
195
196   if (hdr.partition[0].partition_end.ind != PPC_IND)
197     {
198       bfd_set_error (bfd_error_wrong_format);
199       return NULL;
200     }
201
202   abfd->symcount = PPCBOOT_SYMS;
203
204   /* One data section.  */
205   sec = bfd_make_section (abfd, ".data");
206   if (sec == NULL)
207     return NULL;
208   sec->flags = SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_CODE | SEC_HAS_CONTENTS;
209   sec->vma = 0;
210   sec->_raw_size = statbuf.st_size - sizeof (ppcboot_hdr_t);
211   sec->filepos = sizeof (ppcboot_hdr_t);
212
213   ppcboot_mkobject (abfd);
214   tdata = ppcboot_get_tdata (abfd);
215   tdata->sec = sec;
216   memcpy ((PTR) &tdata->header, (PTR) &hdr, sizeof (ppcboot_hdr_t));
217
218   ppcboot_set_arch_mach (abfd, bfd_arch_powerpc, 0);
219   return abfd->xvec;
220 }
221
222 #define ppcboot_close_and_cleanup _bfd_generic_close_and_cleanup
223 #define ppcboot_bfd_free_cached_info _bfd_generic_bfd_free_cached_info
224 #define ppcboot_new_section_hook _bfd_generic_new_section_hook
225
226 \f
227 /* Get contents of the only section.  */
228
229 static boolean
230 ppcboot_get_section_contents (abfd, section, location, offset, count)
231      bfd *abfd;
232      asection *section ATTRIBUTE_UNUSED;
233      PTR location;
234      file_ptr offset;
235      bfd_size_type count;
236 {
237   if (bfd_seek (abfd, offset + sizeof(ppcboot_hdr_t), SEEK_SET) != 0
238       || bfd_read (location, 1, count, abfd) != count)
239     return false;
240   return true;
241 }
242
243 \f
244 /* Return the amount of memory needed to read the symbol table.  */
245
246 static long
247 ppcboot_get_symtab_upper_bound (abfd)
248      bfd *abfd ATTRIBUTE_UNUSED;
249 {
250   return (PPCBOOT_SYMS + 1) * sizeof (asymbol *);
251 }
252
253 \f
254 /* Create a symbol name based on the bfd's filename.  */
255
256 static char *
257 mangle_name (abfd, suffix)
258      bfd *abfd;
259      char *suffix;
260 {
261   int size;
262   char *buf;
263   char *p;
264
265   size = (strlen (bfd_get_filename (abfd))
266           + strlen (suffix)
267           + sizeof "_ppcboot__");
268
269   buf = (char *) bfd_alloc (abfd, size);
270   if (buf == NULL)
271     return "";
272
273   sprintf (buf, "_ppcboot_%s_%s", bfd_get_filename (abfd), suffix);
274
275   /* Change any non-alphanumeric characters to underscores.  */
276   for (p = buf; *p; p++)
277     if (! isalnum ((unsigned char) *p))
278       *p = '_';
279
280   return buf;
281 }
282
283 \f
284 /* Return the symbol table.  */
285
286 static long
287 ppcboot_get_symtab (abfd, alocation)
288      bfd *abfd;
289      asymbol **alocation;
290 {
291   asection *sec = ppcboot_get_tdata (abfd)->sec;
292   asymbol *syms;
293   unsigned int i;
294
295   syms = (asymbol *) bfd_alloc (abfd, PPCBOOT_SYMS * sizeof (asymbol));
296   if (syms == NULL)
297     return false;
298
299   /* Start symbol.  */
300   syms[0].the_bfd = abfd;
301   syms[0].name = mangle_name (abfd, "start");
302   syms[0].value = 0;
303   syms[0].flags = BSF_GLOBAL;
304   syms[0].section = sec;
305   syms[0].udata.p = NULL;
306
307   /* End symbol.  */
308   syms[1].the_bfd = abfd;
309   syms[1].name = mangle_name (abfd, "end");
310   syms[1].value = sec->_raw_size;
311   syms[1].flags = BSF_GLOBAL;
312   syms[1].section = sec;
313   syms[1].udata.p = NULL;
314
315   /* Size symbol.  */
316   syms[2].the_bfd = abfd;
317   syms[2].name = mangle_name (abfd, "size");
318   syms[2].value = sec->_raw_size;
319   syms[2].flags = BSF_GLOBAL;
320   syms[2].section = bfd_abs_section_ptr;
321   syms[2].udata.p = NULL;
322
323   for (i = 0; i < PPCBOOT_SYMS; i++)
324     *alocation++ = syms++;
325   *alocation = NULL;
326
327   return PPCBOOT_SYMS;
328 }
329
330 \f
331 /* Make an empty symbol.  */
332
333 static asymbol *
334 ppcboot_make_empty_symbol (abfd)
335      bfd *abfd;
336 {
337   return (asymbol *) bfd_alloc (abfd, sizeof (asymbol));
338 }
339
340 \f
341 #define ppcboot_print_symbol _bfd_nosymbols_print_symbol
342
343 /* Get information about a symbol.  */
344
345 static void
346 ppcboot_get_symbol_info (ignore_abfd, symbol, ret)
347      bfd *ignore_abfd ATTRIBUTE_UNUSED;
348      asymbol *symbol;
349      symbol_info *ret;
350 {
351   bfd_symbol_info (symbol, ret);
352 }
353
354 #define ppcboot_bfd_is_local_label_name bfd_generic_is_local_label_name
355 #define ppcboot_get_lineno _bfd_nosymbols_get_lineno
356 #define ppcboot_find_nearest_line _bfd_nosymbols_find_nearest_line
357 #define ppcboot_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol
358 #define ppcboot_read_minisymbols _bfd_generic_read_minisymbols
359 #define ppcboot_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol
360
361 #define ppcboot_get_reloc_upper_bound \
362   ((long (*) PARAMS ((bfd *, asection *))) bfd_0l)
363 #define ppcboot_canonicalize_reloc \
364   ((long (*) PARAMS ((bfd *, asection *, arelent **, asymbol **))) bfd_0l)
365 #define ppcboot_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup
366 \f
367 /* Write section contents of a ppcboot file.  */
368
369 static boolean
370 ppcboot_set_section_contents (abfd, sec, data, offset, size)
371      bfd *abfd;
372      asection *sec;
373      PTR data;
374      file_ptr offset;
375      bfd_size_type size;
376 {
377   if (! abfd->output_has_begun)
378     {
379       bfd_vma low;
380       asection *s;
381
382       /* The lowest section VMA sets the virtual address of the start
383          of the file.  We use the set the file position of all the
384          sections.  */
385       low = abfd->sections->vma;
386       for (s = abfd->sections->next; s != NULL; s = s->next)
387         if (s->vma < low)
388           low = s->vma;
389
390       for (s = abfd->sections; s != NULL; s = s->next)
391         s->filepos = s->vma - low;
392
393       abfd->output_has_begun = true;
394     }
395
396   return _bfd_generic_set_section_contents (abfd, sec, data, offset, size);
397 }
398
399 \f
400 static int
401 ppcboot_sizeof_headers (abfd, exec)
402      bfd *abfd ATTRIBUTE_UNUSED;
403      boolean exec ATTRIBUTE_UNUSED;
404 {
405   return sizeof (ppcboot_hdr_t);
406 }
407
408 \f
409 /* Print out the program headers.  */
410
411 static boolean
412 ppcboot_bfd_print_private_bfd_data (abfd, farg)
413      bfd *abfd;
414      PTR farg;
415 {
416   FILE *f = (FILE *)farg;
417   ppcboot_data_t *tdata = ppcboot_get_tdata (abfd);
418   long entry_offset = bfd_getl_signed_32 ((PTR) tdata->header.entry_offset);
419   long length = bfd_getl_signed_32 ((PTR) tdata->header.length);
420   int i;
421
422   fprintf (f, _("\nppcboot header:\n"));
423   fprintf (f, _("Entry offset        = 0x%.8lx (%ld)\n"), entry_offset, entry_offset);
424   fprintf (f, _("Length              = 0x%.8lx (%ld)\n"), length, length);
425
426   if (tdata->header.flags)
427     fprintf (f, _("Flag field          = 0x%.2x\n"), tdata->header.flags);
428
429   if (tdata->header.os_id)
430     fprintf (f, "OS_ID               = 0x%.2x\n", tdata->header.os_id);
431
432   if (tdata->header.partition_name)
433     fprintf (f, _("Partition name      = \"%s\"\n"), tdata->header.partition_name);
434
435   for (i = 0; i < 4; i++)
436     {
437       long sector_begin  = bfd_getl_signed_32 ((PTR) tdata->header.partition[i].sector_begin);
438       long sector_length = bfd_getl_signed_32 ((PTR) tdata->header.partition[i].sector_length);
439
440       /* Skip all 0 entries */
441       if (!tdata->header.partition[i].partition_begin.ind
442           && !tdata->header.partition[i].partition_begin.head
443           && !tdata->header.partition[i].partition_begin.sector
444           && !tdata->header.partition[i].partition_begin.cylinder
445           && !tdata->header.partition[i].partition_end.ind
446           && !tdata->header.partition[i].partition_end.head
447           && !tdata->header.partition[i].partition_end.sector
448           && !tdata->header.partition[i].partition_end.cylinder
449           && !sector_begin && !sector_length)
450         continue;
451
452       fprintf (f, _("\nPartition[%d] start  = { 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x }\n"), i,
453                tdata->header.partition[i].partition_begin.ind,
454                tdata->header.partition[i].partition_begin.head,
455                tdata->header.partition[i].partition_begin.sector,
456                tdata->header.partition[i].partition_begin.cylinder);
457
458       fprintf (f, _("Partition[%d] end    = { 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x }\n"), i,
459                tdata->header.partition[i].partition_end.ind,
460                tdata->header.partition[i].partition_end.head,
461                tdata->header.partition[i].partition_end.sector,
462                tdata->header.partition[i].partition_end.cylinder);
463
464       fprintf (f, _("Partition[%d] sector = 0x%.8lx (%ld)\n"), i, sector_begin, sector_begin);
465       fprintf (f, _("Partition[%d] length = 0x%.8lx (%ld)\n"), i, sector_length, sector_length);
466     }
467
468   fprintf (f, "\n");
469   return true;
470 }
471
472 \f
473 #define ppcboot_bfd_get_relocated_section_contents \
474   bfd_generic_get_relocated_section_contents
475 #define ppcboot_bfd_relax_section bfd_generic_relax_section
476 #define ppcboot_bfd_gc_sections bfd_generic_gc_sections
477 #define ppcboot_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
478 #define ppcboot_bfd_link_add_symbols _bfd_generic_link_add_symbols
479 #define ppcboot_bfd_final_link _bfd_generic_final_link
480 #define ppcboot_bfd_link_split_section _bfd_generic_link_split_section
481 #define ppcboot_get_section_contents_in_window \
482   _bfd_generic_get_section_contents_in_window
483
484 #define ppcboot_bfd_copy_private_bfd_data _bfd_generic_bfd_copy_private_bfd_data
485 #define ppcboot_bfd_merge_private_bfd_data _bfd_generic_bfd_merge_private_bfd_data
486 #define ppcboot_bfd_copy_private_section_data _bfd_generic_bfd_copy_private_section_data
487 #define ppcboot_bfd_copy_private_symbol_data _bfd_generic_bfd_copy_private_symbol_data
488 #define ppcboot_bfd_set_private_flags _bfd_generic_bfd_set_private_flags
489 #define ppcboot_bfd_print_private_bfd_dat ppcboot_bfd_print_private_bfd_data
490
491 const bfd_target ppcboot_vec =
492 {
493   "ppcboot",                    /* name */
494   bfd_target_unknown_flavour,   /* flavour */
495   BFD_ENDIAN_BIG,               /* byteorder is big endian for code */
496   BFD_ENDIAN_LITTLE,            /* header_byteorder */
497   EXEC_P,                       /* object_flags */
498   (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA
499    | SEC_ROM | SEC_HAS_CONTENTS), /* section_flags */
500   0,                            /* symbol_leading_char */
501   ' ',                          /* ar_pad_char */
502   16,                           /* ar_max_namelen */
503   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
504   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
505   bfd_getb16, bfd_getb_signed_16, bfd_putb16,   /* data */
506   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
507   bfd_getl32, bfd_getl_signed_32, bfd_putl32,
508   bfd_getl16, bfd_getl_signed_16, bfd_putl16,   /* hdrs */
509   {                             /* bfd_check_format */
510     _bfd_dummy_target,
511     ppcboot_object_p,           /* bfd_check_format */
512     _bfd_dummy_target,
513     _bfd_dummy_target,
514   },
515   {                             /* bfd_set_format */
516     bfd_false,
517     ppcboot_mkobject,
518     bfd_false,
519     bfd_false,
520   },
521   {                             /* bfd_write_contents */
522     bfd_false,
523     bfd_true,
524     bfd_false,
525     bfd_false,
526   },
527
528   BFD_JUMP_TABLE_GENERIC (ppcboot),
529   BFD_JUMP_TABLE_COPY (ppcboot),
530   BFD_JUMP_TABLE_CORE (_bfd_nocore),
531   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
532   BFD_JUMP_TABLE_SYMBOLS (ppcboot),
533   BFD_JUMP_TABLE_RELOCS (ppcboot),
534   BFD_JUMP_TABLE_WRITE (ppcboot),
535   BFD_JUMP_TABLE_LINK (ppcboot),
536   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
537
538   NULL,
539   
540   NULL
541 };