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