Fix code to check for illegal element numbers when accessing AArch64 vector registers...
[external/binutils.git] / sim / aarch64 / memory.c
1 /* memory.c -- Memory accessor functions for the AArch64 simulator
2
3    Copyright (C) 2015-2016 Free Software Foundation, Inc.
4
5    Contributed by Red Hat.
6
7    This file is part of GDB.
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21
22 #include "config.h"
23 #include <sys/types.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "bfd.h"
29 #include "libbfd.h"
30 #include "libiberty.h"
31 #include "elf/internal.h"
32 #include "elf/common.h"
33
34 #include "memory.h"
35 #include "simulator.h"
36
37 #include "sim-core.h"
38
39 static inline void
40 mem_error (sim_cpu *cpu, const char *message, uint64_t addr)
41 {
42   TRACE_MEMORY (cpu, "ERROR: %s: %" PRIx64, message, addr);
43 }
44
45 #define FETCH_FUNC(RETURN_TYPE, ACCESS_TYPE, NAME, N)                   \
46   RETURN_TYPE                                                           \
47   aarch64_get_mem_##NAME (sim_cpu *cpu, uint64_t address)               \
48   {                                                                     \
49     RETURN_TYPE val = (RETURN_TYPE) sim_core_read_##N (cpu, 0, read_map, address); \
50     TRACE_MEMORY (cpu,                                                  \
51                   "read of %" PRIx64 " (%d bytes) from %" PRIx64,       \
52                   (uint64_t) val, N, address);                          \
53                                                                         \
54     return val;                                                         \
55   }
56
57 /* A variant of the FETCH_FUNC macro that uses unaligned reads.
58    The AArch64 only requires 4-byte alignment for 8-byte quantities
59    but the sim common core does not support this.  */
60 #define FETCH_FUNC_U(RETURN_TYPE, ACCESS_TYPE, NAME)                    \
61   RETURN_TYPE                                                           \
62   aarch64_get_mem_##NAME (sim_cpu *cpu, uint64_t address)               \
63   {                                                                     \
64     RETURN_TYPE val = (RETURN_TYPE) sim_core_read_unaligned_8 (cpu, 0, read_map, address); \
65     TRACE_MEMORY (cpu,                                                  \
66                   "read of %" PRIx64 " (%d bytes) from %" PRIx64 " (unaligned double)", \
67                   (uint64_t) val, N, address);                          \
68                                                                         \
69     return val;                                                         \
70   }
71
72 FETCH_FUNC_U (uint64_t, uint64_t, u64)
73 FETCH_FUNC_U (int64_t,   int64_t, s64)
74 FETCH_FUNC (uint32_t,   uint32_t, u32, 4)
75 FETCH_FUNC (int32_t,     int32_t, s32, 4)
76 FETCH_FUNC (uint32_t,   uint16_t, u16, 2)
77 FETCH_FUNC (int32_t,     int16_t, s16, 2)
78 FETCH_FUNC (uint32_t,    uint8_t, u8, 1)
79 FETCH_FUNC (int32_t,      int8_t, s8, 1)
80
81 void
82 aarch64_get_mem_long_double (sim_cpu *cpu, uint64_t address, FRegister *a)
83 {
84   a->v[0] = sim_core_read_unaligned_8 (cpu, 0, read_map, address);
85   a->v[1] = sim_core_read_unaligned_8 (cpu, 0, read_map, address + 8);
86 }
87
88 #define STORE_FUNC(TYPE, NAME, N)                                       \
89   void                                                                  \
90   aarch64_set_mem_##NAME (sim_cpu *cpu, uint64_t address, TYPE value)   \
91   {                                                                     \
92     TRACE_MEMORY (cpu,                                                  \
93                   "write of %" PRIx64 " (%d bytes) to %" PRIx64,        \
94                   (uint64_t) value, N, address);                        \
95                                                                         \
96     sim_core_write_unaligned_##N (cpu, 0, write_map, address, value);   \
97   }
98
99 /* A variant of the STORE_FUNC macro that uses unaligned writes.
100    The AArch64 only requires 4-byte alignment for 8-byte quantities
101    but the sim common core does not support this.  */
102 #define STORE_FUNC_U(TYPE, NAME)                                        \
103   void                                                                  \
104   aarch64_set_mem_##NAME (sim_cpu *cpu, uint64_t address, TYPE value)   \
105   {                                                                     \
106     TRACE_MEMORY (cpu,                                                  \
107                   "write of %" PRIx64 " (8 bytes) to %" PRIx64,         \
108                   (uint64_t) value, address);                           \
109                                                                         \
110     sim_core_write_unaligned_8 (cpu, 0, write_map, address, value);     \
111   }
112
113 STORE_FUNC_U (uint64_t, u64)
114 STORE_FUNC_U (int64_t,  s64)
115 STORE_FUNC (uint32_t,   u32, 4)
116 STORE_FUNC (int32_t,    s32, 4)
117 STORE_FUNC (uint16_t,   u16, 2)
118 STORE_FUNC (int16_t,    s16, 2)
119 STORE_FUNC (uint8_t,    u8, 1)
120 STORE_FUNC (int8_t,     s8, 1)
121
122 void
123 aarch64_set_mem_long_double (sim_cpu *cpu, uint64_t address, FRegister a)
124 {
125   TRACE_MEMORY (cpu,
126                 "write of long double %" PRIx64 " %" PRIx64 " to %" PRIx64,
127                 a.v[0], a.v[1], address);
128
129   sim_core_write_unaligned_8 (cpu, 0, write_map, address, a.v[0]);
130   sim_core_write_unaligned_8 (cpu, 0, write_map, address + 8, a.v[1]);
131 }
132
133 void
134 aarch64_get_mem_blk (sim_cpu *  cpu,
135                      uint64_t   address,
136                      char *     buffer,
137                      unsigned   length)
138 {
139   unsigned len;
140
141   len = sim_core_read_buffer (CPU_STATE (cpu), cpu, read_map,
142                               buffer, address, length);
143   if (len == length)
144     return;
145
146   memset (buffer, 0, length);
147   if (cpu)
148     mem_error (cpu, "read of non-existant mem block at", address);
149
150   sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
151                    sim_stopped, SIM_SIGBUS);
152 }
153
154 const char *
155 aarch64_get_mem_ptr (sim_cpu *cpu, uint64_t address)
156 {
157   char *addr = sim_core_trans_addr (CPU_STATE (cpu), cpu, read_map, address);
158
159   if (addr == NULL)
160     {
161       mem_error (cpu, "request for non-existant mem addr of", address);
162       sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
163                        sim_stopped, SIM_SIGBUS);
164     }
165
166   return addr;
167 }
168
169 /* We implement a combined stack and heap.  That way the sbrk()
170    function in libgloss/aarch64/syscalls.c has a chance to detect
171    an out-of-memory condition by noticing a stack/heap collision.
172
173    The heap starts at the end of loaded memory and carries on up
174    to an arbitary 2Gb limit.  */
175
176 uint64_t
177 aarch64_get_heap_start (sim_cpu *cpu)
178 {
179   uint64_t heap = aarch64_get_sym_value ("end");
180
181   if (heap == 0)
182     heap = aarch64_get_sym_value ("_end");
183   if (heap == 0)
184     {
185       heap = STACK_TOP - 0x100000;
186       sim_io_eprintf (CPU_STATE (cpu),
187                       "Unable to find 'end' symbol - using addr based "
188                       "upon stack instead %" PRIx64 "\n",
189                       heap);
190     }
191   return heap;
192 }
193
194 uint64_t
195 aarch64_get_stack_start (sim_cpu *cpu)
196 {
197   if (aarch64_get_heap_start (cpu) >= STACK_TOP)
198     mem_error (cpu, "executable is too big", aarch64_get_heap_start (cpu));
199   return STACK_TOP;
200 }