1/* load.c --- loading object files into the RX simulator.
2
3Copyright (C) 2005-2023 Free Software Foundation, Inc.
4Contributed by Red Hat, Inc.
5
6This file is part of the GNU simulators.
7
8This program is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 3 of the License, or
11(at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20
21/* This must come before any other includes.  */
22#include "defs.h"
23
24#include <stdlib.h>
25#include <stdio.h>
26#include <string.h>
27
28#include "bfd.h"
29#include "cpu.h"
30#include "mem.h"
31#include "load.h"
32#include "elf-bfd.h"
33
34/* Helper function for invoking a GDB-specified printf.  */
35static void
36xprintf (host_callback *callback, const char *fmt, ...)
37{
38  va_list ap;
39
40  va_start (ap, fmt);
41
42  (*callback->vprintf_filtered) (callback, fmt, ap);
43
44  va_end (ap);
45}
46
47/* Given a file offset, look up the section name.  */
48static const char *
49find_section_name_by_offset (bfd *abfd, file_ptr filepos)
50{
51  asection *s;
52
53  for (s = abfd->sections; s; s = s->next)
54    if (s->filepos == filepos)
55      return bfd_section_name (s);
56
57  return "(unknown)";
58}
59
60/* A note about endianness and swapping...
61
62   The RX chip is CISC-like in that the opcodes are variable length
63   and are read as a stream of bytes.  However, the chip itself shares
64   the code prefetch block with the data fetch block, so when it's
65   configured for big endian mode, the memory fetched for opcodes is
66   word-swapped.  To compensate for this, the ELF file has the code
67   sections pre-swapped.  Our BFD knows this, and for the convenience
68   of all the other tools, hides this swapping at a very low level.
69   I.e.  it swaps words on the way out and on the way back in.
70
71   Fortunately the iovector routines are unaffected by this, so we
72   can use them to read in the segments directly, without having
73   to worry about byte swapping anything.
74
75   However, our opcode decoder and disassemblers need to swap the data
76   after reading it from the chip memory, just like the chip does.
77   All in all, the code words are swapped four times between the
78   assembler and our decoder.
79
80   If the chip is running in little-endian mode, no swapping is done
81   anywhere.  Note also that the *operands* within opcodes are always
82   encoded in little-endian format.  */
83
84void
85rx_load (bfd *prog, host_callback *callback)
86{
87  unsigned long highest_addr_loaded = 0;
88  Elf_Internal_Phdr * phdrs;
89  long sizeof_phdrs;
90  int num_headers;
91  int i;
92
93  rx_big_endian = bfd_big_endian (prog);
94
95  /* Note we load by ELF program header not by BFD sections.
96     This is because BFD sections get their information from
97     the ELF section structure, which only includes a VMA value
98     and not an LMA value.  */
99  sizeof_phdrs = bfd_get_elf_phdr_upper_bound (prog);
100  if (sizeof_phdrs == 0)
101    {
102      fprintf (stderr, "Failed to get size of program headers\n");
103      return;
104    }
105  phdrs = malloc (sizeof_phdrs);
106  if (phdrs == NULL)
107    {
108      fprintf (stderr, "Failed allocate memory to hold program headers\n");
109      return;
110    }
111  num_headers = bfd_get_elf_phdrs (prog, phdrs);
112  if (num_headers < 1)
113    {
114      fprintf (stderr, "Failed to read program headers\n");
115      return;
116    }
117
118  for (i = 0; i < num_headers; i++)
119    {
120      Elf_Internal_Phdr * p = phdrs + i;
121      char *buf;
122      bfd_vma size;
123      bfd_vma base;
124      file_ptr offset;
125
126      size = p->p_filesz;
127      if (size <= 0)
128	continue;
129
130      base = p->p_paddr;
131      if (verbose > 1)
132	fprintf (stderr,
133		 "[load segment: lma=%08" PRIx64 " vma=%08" PRIx64 " "
134		 "size=%08" PRIx64 "]\n",
135		 (uint64_t) base, (uint64_t) p->p_vaddr, (uint64_t) size);
136      if (callback)
137	xprintf (callback,
138	         "Loading section %s, size %#" PRIx64 " lma %08" PRIx64
139		 " vma %08" PRIx64 "\n",
140	         find_section_name_by_offset (prog, p->p_offset),
141		 (uint64_t) size, (uint64_t) base, (uint64_t) p->p_vaddr);
142
143      buf = malloc (size);
144      if (buf == NULL)
145	{
146	  fprintf (stderr, "Failed to allocate buffer to hold program segment\n");
147	  continue;
148	}
149
150      offset = p->p_offset;
151      if (bfd_seek (prog, offset, SEEK_SET) != 0)
152	{
153	  fprintf (stderr, "Failed to seek to offset %lx\n", (long) offset);
154	  continue;
155	}
156      if (bfd_bread (buf, size, prog) != size)
157	{
158	  fprintf (stderr, "Failed to read %" PRIx64 " bytes\n",
159		   (uint64_t) size);
160	  continue;
161	}
162
163      mem_put_blk (base, buf, size);
164      free (buf);
165      if (highest_addr_loaded < base + size - 1 && size >= 4)
166	highest_addr_loaded = base + size - 1;
167    }
168
169  free (phdrs);
170
171  regs.r_pc = prog->start_address;
172
173  if (strcmp (bfd_get_target (prog), "srec") == 0
174      || regs.r_pc == 0)
175    {
176      regs.r_pc = mem_get_si (0xfffffffc);
177      heaptop = heapbottom = 0;
178    }
179
180  reset_decoder ();
181
182  if (verbose > 1)
183    fprintf (stderr, "[start pc=%08x %s]\n",
184	     (unsigned int) regs.r_pc,
185	     rx_big_endian ? "BE" : "LE");
186}
187