xref: /netbsd-src/external/gpl3/gdb/dist/sim/rx/load.c (revision 1f4e7eb9e5e045e008f1894823a8e4e6c9f46890)
14e98e3e1Schristos /* load.c --- loading object files into the RX simulator.
24e98e3e1Schristos 
3*1f4e7eb9Schristos Copyright (C) 2005-2024 Free Software Foundation, Inc.
44e98e3e1Schristos Contributed by Red Hat, Inc.
54e98e3e1Schristos 
64e98e3e1Schristos This file is part of the GNU simulators.
74e98e3e1Schristos 
84e98e3e1Schristos This program is free software; you can redistribute it and/or modify
94e98e3e1Schristos it under the terms of the GNU General Public License as published by
104e98e3e1Schristos the Free Software Foundation; either version 3 of the License, or
114e98e3e1Schristos (at your option) any later version.
124e98e3e1Schristos 
134e98e3e1Schristos This program is distributed in the hope that it will be useful,
144e98e3e1Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
154e98e3e1Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
164e98e3e1Schristos GNU General Public License for more details.
174e98e3e1Schristos 
184e98e3e1Schristos You should have received a copy of the GNU General Public License
194e98e3e1Schristos along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
204e98e3e1Schristos 
214b169a6bSchristos /* This must come before any other includes.  */
224b169a6bSchristos #include "defs.h"
234e98e3e1Schristos 
244e98e3e1Schristos #include <stdlib.h>
254e98e3e1Schristos #include <stdio.h>
264e98e3e1Schristos #include <string.h>
274e98e3e1Schristos 
284e98e3e1Schristos #include "bfd.h"
294e98e3e1Schristos #include "cpu.h"
304e98e3e1Schristos #include "mem.h"
31a2e2270fSchristos #include "load.h"
32*1f4e7eb9Schristos #include "bfd/elf-bfd.h"
334e98e3e1Schristos 
34a2e2270fSchristos /* Helper function for invoking a GDB-specified printf.  */
35a2e2270fSchristos static void
36a2e2270fSchristos xprintf (host_callback *callback, const char *fmt, ...)
37a2e2270fSchristos {
38a2e2270fSchristos   va_list ap;
39a2e2270fSchristos 
40a2e2270fSchristos   va_start (ap, fmt);
41a2e2270fSchristos 
42a2e2270fSchristos   (*callback->vprintf_filtered) (callback, fmt, ap);
43a2e2270fSchristos 
44a2e2270fSchristos   va_end (ap);
45a2e2270fSchristos }
46a2e2270fSchristos 
47a2e2270fSchristos /* Given a file offset, look up the section name.  */
48a2e2270fSchristos static const char *
49a2e2270fSchristos find_section_name_by_offset (bfd *abfd, file_ptr filepos)
50a2e2270fSchristos {
51a2e2270fSchristos   asection *s;
52a2e2270fSchristos 
53a2e2270fSchristos   for (s = abfd->sections; s; s = s->next)
54a2e2270fSchristos     if (s->filepos == filepos)
558dffb485Schristos       return bfd_section_name (s);
56a2e2270fSchristos 
57a2e2270fSchristos   return "(unknown)";
58a2e2270fSchristos }
59a2e2270fSchristos 
604e98e3e1Schristos /* A note about endianness and swapping...
614e98e3e1Schristos 
624e98e3e1Schristos    The RX chip is CISC-like in that the opcodes are variable length
634e98e3e1Schristos    and are read as a stream of bytes.  However, the chip itself shares
644e98e3e1Schristos    the code prefetch block with the data fetch block, so when it's
654e98e3e1Schristos    configured for big endian mode, the memory fetched for opcodes is
664e98e3e1Schristos    word-swapped.  To compensate for this, the ELF file has the code
674e98e3e1Schristos    sections pre-swapped.  Our BFD knows this, and for the convenience
684e98e3e1Schristos    of all the other tools, hides this swapping at a very low level.
694e98e3e1Schristos    I.e.  it swaps words on the way out and on the way back in.
704e98e3e1Schristos 
714e98e3e1Schristos    Fortunately the iovector routines are unaffected by this, so we
724e98e3e1Schristos    can use them to read in the segments directly, without having
734e98e3e1Schristos    to worry about byte swapping anything.
744e98e3e1Schristos 
754e98e3e1Schristos    However, our opcode decoder and disassemblers need to swap the data
764e98e3e1Schristos    after reading it from the chip memory, just like the chip does.
774e98e3e1Schristos    All in all, the code words are swapped four times between the
784e98e3e1Schristos    assembler and our decoder.
794e98e3e1Schristos 
804e98e3e1Schristos    If the chip is running in little-endian mode, no swapping is done
814e98e3e1Schristos    anywhere.  Note also that the *operands* within opcodes are always
824e98e3e1Schristos    encoded in little-endian format.  */
834e98e3e1Schristos 
844e98e3e1Schristos void
85a2e2270fSchristos rx_load (bfd *prog, host_callback *callback)
864e98e3e1Schristos {
874e98e3e1Schristos   unsigned long highest_addr_loaded = 0;
884e98e3e1Schristos   Elf_Internal_Phdr * phdrs;
894e98e3e1Schristos   long sizeof_phdrs;
904e98e3e1Schristos   int num_headers;
914e98e3e1Schristos   int i;
924e98e3e1Schristos 
934e98e3e1Schristos   rx_big_endian = bfd_big_endian (prog);
944e98e3e1Schristos 
954e98e3e1Schristos   /* Note we load by ELF program header not by BFD sections.
964e98e3e1Schristos      This is because BFD sections get their information from
974e98e3e1Schristos      the ELF section structure, which only includes a VMA value
984e98e3e1Schristos      and not an LMA value.  */
994e98e3e1Schristos   sizeof_phdrs = bfd_get_elf_phdr_upper_bound (prog);
1004e98e3e1Schristos   if (sizeof_phdrs == 0)
1014e98e3e1Schristos     {
1024e98e3e1Schristos       fprintf (stderr, "Failed to get size of program headers\n");
1034e98e3e1Schristos       return;
1044e98e3e1Schristos     }
1054e98e3e1Schristos   phdrs = malloc (sizeof_phdrs);
1064e98e3e1Schristos   if (phdrs == NULL)
1074e98e3e1Schristos     {
1084e98e3e1Schristos       fprintf (stderr, "Failed allocate memory to hold program headers\n");
1094e98e3e1Schristos       return;
1104e98e3e1Schristos     }
1114e98e3e1Schristos   num_headers = bfd_get_elf_phdrs (prog, phdrs);
1124e98e3e1Schristos   if (num_headers < 1)
1134e98e3e1Schristos     {
1144e98e3e1Schristos       fprintf (stderr, "Failed to read program headers\n");
1154e98e3e1Schristos       return;
1164e98e3e1Schristos     }
1174e98e3e1Schristos 
1184e98e3e1Schristos   for (i = 0; i < num_headers; i++)
1194e98e3e1Schristos     {
1204e98e3e1Schristos       Elf_Internal_Phdr * p = phdrs + i;
1214e98e3e1Schristos       char *buf;
1224e98e3e1Schristos       bfd_vma size;
1234e98e3e1Schristos       bfd_vma base;
1244e98e3e1Schristos       file_ptr offset;
1254e98e3e1Schristos 
1264e98e3e1Schristos       size = p->p_filesz;
1274e98e3e1Schristos       if (size <= 0)
1284e98e3e1Schristos 	continue;
1294e98e3e1Schristos 
1304e98e3e1Schristos       base = p->p_paddr;
1314e98e3e1Schristos       if (verbose > 1)
1324b169a6bSchristos 	fprintf (stderr,
1334b169a6bSchristos 		 "[load segment: lma=%08" PRIx64 " vma=%08" PRIx64 " "
1344b169a6bSchristos 		 "size=%08" PRIx64 "]\n",
1354b169a6bSchristos 		 (uint64_t) base, (uint64_t) p->p_vaddr, (uint64_t) size);
136a2e2270fSchristos       if (callback)
137a2e2270fSchristos 	xprintf (callback,
1384b169a6bSchristos 	         "Loading section %s, size %#" PRIx64 " lma %08" PRIx64
1394b169a6bSchristos 		 " vma %08" PRIx64 "\n",
140a2e2270fSchristos 	         find_section_name_by_offset (prog, p->p_offset),
1414b169a6bSchristos 		 (uint64_t) size, (uint64_t) base, (uint64_t) p->p_vaddr);
1424e98e3e1Schristos 
1434e98e3e1Schristos       buf = malloc (size);
1444e98e3e1Schristos       if (buf == NULL)
1454e98e3e1Schristos 	{
1464e98e3e1Schristos 	  fprintf (stderr, "Failed to allocate buffer to hold program segment\n");
1474e98e3e1Schristos 	  continue;
1484e98e3e1Schristos 	}
1494e98e3e1Schristos 
1504e98e3e1Schristos       offset = p->p_offset;
151ba340e45Schristos       if (bfd_seek (prog, offset, SEEK_SET) != 0)
1524e98e3e1Schristos 	{
1534e98e3e1Schristos 	  fprintf (stderr, "Failed to seek to offset %lx\n", (long) offset);
1544e98e3e1Schristos 	  continue;
1554e98e3e1Schristos 	}
156*1f4e7eb9Schristos       if (bfd_read (buf, size, prog) != size)
1574e98e3e1Schristos 	{
1584b169a6bSchristos 	  fprintf (stderr, "Failed to read %" PRIx64 " bytes\n",
1594b169a6bSchristos 		   (uint64_t) size);
1604e98e3e1Schristos 	  continue;
1614e98e3e1Schristos 	}
1624e98e3e1Schristos 
1634e98e3e1Schristos       mem_put_blk (base, buf, size);
1644e98e3e1Schristos       free (buf);
1654e98e3e1Schristos       if (highest_addr_loaded < base + size - 1 && size >= 4)
1664e98e3e1Schristos 	highest_addr_loaded = base + size - 1;
1674e98e3e1Schristos     }
1684e98e3e1Schristos 
1694e98e3e1Schristos   free (phdrs);
1704e98e3e1Schristos 
1714e98e3e1Schristos   regs.r_pc = prog->start_address;
1724e98e3e1Schristos 
1734e98e3e1Schristos   if (strcmp (bfd_get_target (prog), "srec") == 0
1744e98e3e1Schristos       || regs.r_pc == 0)
1754e98e3e1Schristos     {
1764e98e3e1Schristos       regs.r_pc = mem_get_si (0xfffffffc);
1774e98e3e1Schristos       heaptop = heapbottom = 0;
1784e98e3e1Schristos     }
1794e98e3e1Schristos 
1804e98e3e1Schristos   reset_decoder ();
1814e98e3e1Schristos 
1824e98e3e1Schristos   if (verbose > 1)
1834e98e3e1Schristos     fprintf (stderr, "[start pc=%08x %s]\n",
1844e98e3e1Schristos 	     (unsigned int) regs.r_pc,
1854e98e3e1Schristos 	     rx_big_endian ? "BE" : "LE");
1864e98e3e1Schristos }
187