1 /* m32r exception, interrupt, and trap (EIT) support
2 Copyright (C) 1998-2020 Free Software Foundation, Inc.
3 Contributed by Renesas.
5 This file is part of GDB, the GNU debugger.
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 3 of the License, or
10 (at your option) any later version.
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.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 #include "sim-syscall.h"
23 #include "targ-vals.h"
32 #include <sys/resource.h>
33 #include <sys/sysinfo.h>
36 #include <sys/timeb.h>
37 #include <sys/timex.h>
38 #include <sys/types.h>
40 #include <sys/utsname.h>
42 #include <linux/sysctl.h>
43 #include <linux/types.h>
44 #include <linux/unistd.h>
46 #define TRAP_ELF_SYSCALL 0
47 #define TRAP_LINUX_SYSCALL 2
48 #define TRAP_FLUSH_CACHE 12
50 /* The semantic code invokes this for invalid (unrecognized) instructions. */
53 sim_engine_invalid_insn (SIM_CPU *current_cpu, IADDR cia, SEM_PC vpc)
55 SIM_DESC sd = CPU_STATE (current_cpu);
58 if (STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT)
60 h_bsm_set (current_cpu, h_sm_get (current_cpu));
61 h_bie_set (current_cpu, h_ie_get (current_cpu));
62 h_bcond_set (current_cpu, h_cond_get (current_cpu));
64 h_ie_set (current_cpu, 0);
65 h_cond_set (current_cpu, 0);
67 h_bpc_set (current_cpu, cia);
69 sim_engine_restart (CPU_STATE (current_cpu), current_cpu, NULL,
74 sim_engine_halt (sd, current_cpu, NULL, cia, sim_stopped, SIM_SIGILL);
78 /* Process an address exception. */
81 m32r_core_signal (SIM_DESC sd, SIM_CPU *current_cpu, sim_cia cia,
82 unsigned int map, int nr_bytes, address_word addr,
83 transfer_type transfer, sim_core_signals sig)
85 if (STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT)
87 m32rbf_h_cr_set (current_cpu, H_CR_BBPC,
88 m32rbf_h_cr_get (current_cpu, H_CR_BPC));
89 if (MACH_NUM (CPU_MACH (current_cpu)) == MACH_M32R)
91 m32rbf_h_bpsw_set (current_cpu, m32rbf_h_psw_get (current_cpu));
93 m32rbf_h_psw_set (current_cpu, m32rbf_h_psw_get (current_cpu) & 0x80);
95 else if (MACH_NUM (CPU_MACH (current_cpu)) == MACH_M32RX)
97 m32rxf_h_bpsw_set (current_cpu, m32rxf_h_psw_get (current_cpu));
99 m32rxf_h_psw_set (current_cpu, m32rxf_h_psw_get (current_cpu) & 0x80);
103 m32r2f_h_bpsw_set (current_cpu, m32r2f_h_psw_get (current_cpu));
105 m32r2f_h_psw_set (current_cpu, m32r2f_h_psw_get (current_cpu) & 0x80);
107 m32rbf_h_cr_set (current_cpu, H_CR_BPC, cia);
109 sim_engine_restart (CPU_STATE (current_cpu), current_cpu, NULL,
113 sim_core_signal (sd, current_cpu, cia, map, nr_bytes, addr,
117 /* Translate target's address to host's address. */
120 t2h_addr (host_callback *cb, struct cb_syscall *sc,
124 SIM_DESC sd = (SIM_DESC) sc->p1;
125 SIM_CPU *cpu = (SIM_CPU *) sc->p2;
130 return sim_core_trans_addr (sd, cpu, read_map, taddr);
134 conv_endian (unsigned int tvalue)
137 unsigned int t1, t2, t3, t4;
139 if (HOST_BYTE_ORDER == BFD_ENDIAN_LITTLE)
141 t1 = tvalue & 0xff000000;
142 t2 = tvalue & 0x00ff0000;
143 t3 = tvalue & 0x0000ff00;
144 t4 = tvalue & 0x000000ff;
157 static unsigned short
158 conv_endian16 (unsigned short tvalue)
160 unsigned short hvalue;
161 unsigned short t1, t2;
163 if (HOST_BYTE_ORDER == BFD_ENDIAN_LITTLE)
165 t1 = tvalue & 0xff00;
166 t2 = tvalue & 0x00ff;
178 translate_endian(void *addr, size_t size)
180 unsigned int *p = (unsigned int *) addr;
183 for (i = 0; i <= size - 4; i += 4,p++)
184 *p = conv_endian(*p);
187 *((unsigned short *) p) = conv_endian16(*((unsigned short *) p));
191 The result is the pc address to continue at.
192 Preprocessing like saving the various registers has already been done. */
195 m32r_trap (SIM_CPU *current_cpu, PCADDR pc, int num)
197 SIM_DESC sd = CPU_STATE (current_cpu);
198 host_callback *cb = STATE_CALLBACK (sd);
202 case TRAP_ELF_SYSCALL :
204 long result, result2;
207 sim_syscall_multi (current_cpu,
208 m32rbf_h_gr_get (current_cpu, 0),
209 m32rbf_h_gr_get (current_cpu, 1),
210 m32rbf_h_gr_get (current_cpu, 2),
211 m32rbf_h_gr_get (current_cpu, 3),
212 m32rbf_h_gr_get (current_cpu, 4),
213 &result, &result2, &errcode);
215 m32rbf_h_gr_set (current_cpu, 2, errcode);
216 m32rbf_h_gr_set (current_cpu, 0, result);
217 m32rbf_h_gr_set (current_cpu, 1, result2);
221 case TRAP_LINUX_SYSCALL :
224 unsigned int func, arg1, arg2, arg3, arg4, arg5, arg6, arg7;
225 int result, result2, errcode;
227 if (STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT)
229 /* The new pc is the trap vector entry.
230 We assume there's a branch there to some handler.
231 Use cr5 as EVB (EIT Vector Base) register. */
232 USI new_pc = m32rbf_h_cr_get (current_cpu, 5) + 0x40 + num * 4;
236 func = m32rbf_h_gr_get (current_cpu, 7);
237 arg1 = m32rbf_h_gr_get (current_cpu, 0);
238 arg2 = m32rbf_h_gr_get (current_cpu, 1);
239 arg3 = m32rbf_h_gr_get (current_cpu, 2);
240 arg4 = m32rbf_h_gr_get (current_cpu, 3);
241 arg5 = m32rbf_h_gr_get (current_cpu, 4);
242 arg6 = m32rbf_h_gr_get (current_cpu, 5);
243 arg7 = m32rbf_h_gr_get (current_cpu, 6);
245 CB_SYSCALL_INIT (&s);
252 s.p2 = (PTR) current_cpu;
253 s.read_mem = sim_syscall_read_mem;
254 s.write_mem = sim_syscall_write_mem;
263 sim_engine_halt (sd, current_cpu, NULL, pc, sim_exited, arg1);
267 result = read(arg1, t2h_addr(cb, &s, arg2), arg3);
272 result = write(arg1, t2h_addr(cb, &s, arg2), arg3);
277 result = open((char *) t2h_addr(cb, &s, arg1), arg2, arg3);
282 result = close(arg1);
287 result = creat((char *) t2h_addr(cb, &s, arg1), arg2);
292 result = link((char *) t2h_addr(cb, &s, arg1),
293 (char *) t2h_addr(cb, &s, arg2));
298 result = unlink((char *) t2h_addr(cb, &s, arg1));
303 result = chdir((char *) t2h_addr(cb, &s, arg1));
313 result = (int) time(NULL);
318 result = (int) time(&t);
324 translate_endian((void *) &t, sizeof(t));
325 if ((s.write_mem) (cb, &s, arg1, (char *) &t, sizeof(t)) != sizeof(t))
335 result = mknod((char *) t2h_addr(cb, &s, arg1),
336 (mode_t) arg2, (dev_t) arg3);
341 result = chmod((char *) t2h_addr(cb, &s, arg1), (mode_t) arg2);
347 result = lchown((char *) t2h_addr(cb, &s, arg1),
348 (uid_t) arg2, (gid_t) arg3);
353 result = (int) lseek(arg1, (off_t) arg2, arg3);
374 result = utime((char *) t2h_addr(cb, &s, arg1), NULL);
379 buf = *((struct utimbuf *) t2h_addr(cb, &s, arg2));
380 translate_endian((void *) &buf, sizeof(buf));
381 result = utime((char *) t2h_addr(cb, &s, arg1), &buf);
388 result = access((char *) t2h_addr(cb, &s, arg1), arg2);
402 t.time = conv_endian(t.time);
403 t.millitm = conv_endian16(t.millitm);
404 t.timezone = conv_endian16(t.timezone);
405 t.dstflag = conv_endian16(t.dstflag);
406 if ((s.write_mem) (cb, &s, arg1, (char *) &t, sizeof(t))
420 result = rename((char *) t2h_addr(cb, &s, arg1),
421 (char *) t2h_addr(cb, &s, arg2));
426 result = mkdir((char *) t2h_addr(cb, &s, arg1), arg2);
431 result = rmdir((char *) t2h_addr(cb, &s, arg1));
441 result = brk((void *) arg1);
465 result = ioctl(arg1, arg2, arg3);
470 result = fcntl(arg1, arg2, arg3);
475 result = dup2(arg1, arg2);
493 result = getrlimit(arg1, &rlim);
499 translate_endian((void *) &rlim, sizeof(rlim));
500 if ((s.write_mem) (cb, &s, arg2, (char *) &rlim, sizeof(rlim))
513 result = getrusage(arg1, &usage);
519 translate_endian((void *) &usage, sizeof(usage));
520 if ((s.write_mem) (cb, &s, arg2, (char *) &usage, sizeof(usage))
529 case __NR_gettimeofday:
534 result = gettimeofday(&tv, &tz);
540 translate_endian((void *) &tv, sizeof(tv));
541 if ((s.write_mem) (cb, &s, arg1, (char *) &tv, sizeof(tv))
548 translate_endian((void *) &tz, sizeof(tz));
549 if ((s.write_mem) (cb, &s, arg2, (char *) &tz, sizeof(tz))
558 case __NR_getgroups32:
564 list = (gid_t *) malloc(arg1 * sizeof(gid_t));
566 result = getgroups(arg1, list);
572 translate_endian((void *) list, arg1 * sizeof(gid_t));
574 if ((s.write_mem) (cb, &s, arg2, (char *) list, arg1 * sizeof(gid_t))
575 != arg1 * sizeof(gid_t))
595 struct timeval *ttimeoutp;
596 struct timeval timeout;
600 treadfdsp = (fd_set *) arg2;
601 if (treadfdsp != NULL)
603 readfds = *((fd_set *) t2h_addr(cb, &s, (unsigned int) treadfdsp));
604 translate_endian((void *) &readfds, sizeof(readfds));
605 hreadfdsp = &readfds;
610 twritefdsp = (fd_set *) arg3;
611 if (twritefdsp != NULL)
613 writefds = *((fd_set *) t2h_addr(cb, &s, (unsigned int) twritefdsp));
614 translate_endian((void *) &writefds, sizeof(writefds));
615 hwritefdsp = &writefds;
620 texceptfdsp = (fd_set *) arg4;
621 if (texceptfdsp != NULL)
623 exceptfds = *((fd_set *) t2h_addr(cb, &s, (unsigned int) texceptfdsp));
624 translate_endian((void *) &exceptfds, sizeof(exceptfds));
625 hexceptfdsp = &exceptfds;
630 ttimeoutp = (struct timeval *) arg5;
631 timeout = *((struct timeval *) t2h_addr(cb, &s, (unsigned int) ttimeoutp));
632 translate_endian((void *) &timeout, sizeof(timeout));
634 result = select(n, hreadfdsp, hwritefdsp, hexceptfdsp, &timeout);
640 if (treadfdsp != NULL)
642 translate_endian((void *) &readfds, sizeof(readfds));
643 if ((s.write_mem) (cb, &s, (unsigned long) treadfdsp,
644 (char *) &readfds, sizeof(readfds)) != sizeof(readfds))
651 if (twritefdsp != NULL)
653 translate_endian((void *) &writefds, sizeof(writefds));
654 if ((s.write_mem) (cb, &s, (unsigned long) twritefdsp,
655 (char *) &writefds, sizeof(writefds)) != sizeof(writefds))
662 if (texceptfdsp != NULL)
664 translate_endian((void *) &exceptfds, sizeof(exceptfds));
665 if ((s.write_mem) (cb, &s, (unsigned long) texceptfdsp,
666 (char *) &exceptfds, sizeof(exceptfds)) != sizeof(exceptfds))
673 translate_endian((void *) &timeout, sizeof(timeout));
674 if ((s.write_mem) (cb, &s, (unsigned long) ttimeoutp,
675 (char *) &timeout, sizeof(timeout)) != sizeof(timeout))
684 result = symlink((char *) t2h_addr(cb, &s, arg1),
685 (char *) t2h_addr(cb, &s, arg2));
690 result = readlink((char *) t2h_addr(cb, &s, arg1),
691 (char *) t2h_addr(cb, &s, arg2),
697 result = (int) readdir((DIR *) t2h_addr(cb, &s, arg1));
704 result = (int) mmap((void *) t2h_addr(cb, &s, arg1),
705 arg2, arg3, arg4, arg5, arg6);
710 sim_core_attach (sd, NULL,
711 0, access_read_write_exec, 0,
712 result, arg2, 0, NULL, NULL);
721 int prot, flags, fildes;
724 addr = (void *) t2h_addr(cb, &s, arg1);
731 result = (int) mmap(addr, len, prot, flags, fildes, off);
736 if (sim_core_read_buffer (sd, NULL, read_map, &c, result, 1) == 0)
737 sim_core_attach (sd, NULL,
738 0, access_read_write_exec, 0,
739 result, len, 0, NULL, NULL);
748 int prot, flags, fildes;
751 addr = *((void **) t2h_addr(cb, &s, arg1));
752 len = *((size_t *) t2h_addr(cb, &s, arg1 + 4));
753 prot = *((int *) t2h_addr(cb, &s, arg1 + 8));
754 flags = *((int *) t2h_addr(cb, &s, arg1 + 12));
755 fildes = *((int *) t2h_addr(cb, &s, arg1 + 16));
756 off = *((off_t *) t2h_addr(cb, &s, arg1 + 20));
758 addr = (void *) conv_endian((unsigned int) addr);
759 len = conv_endian(len);
760 prot = conv_endian(prot);
761 flags = conv_endian(flags);
762 fildes = conv_endian(fildes);
763 off = conv_endian(off);
765 //addr = (void *) t2h_addr(cb, &s, (unsigned int) addr);
766 result = (int) mmap(addr, len, prot, flags, fildes, off);
773 if (sim_core_read_buffer (sd, NULL, read_map, &c, result, 1) == 0)
774 sim_core_attach (sd, NULL,
775 0, access_read_write_exec, 0,
776 result, len, 0, NULL, NULL);
783 result = munmap((void *)arg1, arg2);
787 sim_core_detach (sd, NULL, 0, arg2, result);
793 result = truncate((char *) t2h_addr(cb, &s, arg1), arg2);
798 result = ftruncate(arg1, arg2);
803 result = fchmod(arg1, arg2);
809 result = fchown(arg1, arg2, arg3);
815 struct statfs statbuf;
817 result = statfs((char *) t2h_addr(cb, &s, arg1), &statbuf);
823 translate_endian((void *) &statbuf, sizeof(statbuf));
824 if ((s.write_mem) (cb, &s, arg2, (char *) &statbuf, sizeof(statbuf))
835 struct statfs statbuf;
837 result = fstatfs(arg1, &statbuf);
843 translate_endian((void *) &statbuf, sizeof(statbuf));
844 if ((s.write_mem) (cb, &s, arg2, (char *) &statbuf, sizeof(statbuf))
854 result = syslog(arg1, (char *) t2h_addr(cb, &s, arg2));
860 struct itimerval value, ovalue;
862 value = *((struct itimerval *) t2h_addr(cb, &s, arg2));
863 translate_endian((void *) &value, sizeof(value));
867 result = setitimer(arg1, &value, NULL);
872 result = setitimer(arg1, &value, &ovalue);
878 translate_endian((void *) &ovalue, sizeof(ovalue));
879 if ((s.write_mem) (cb, &s, arg3, (char *) &ovalue, sizeof(ovalue))
891 struct itimerval value;
893 result = getitimer(arg1, &value);
899 translate_endian((void *) &value, sizeof(value));
900 if ((s.write_mem) (cb, &s, arg2, (char *) &value, sizeof(value))
915 result = stat((char *) t2h_addr(cb, &s, arg1), &statbuf);
920 buflen = cb_host_to_target_stat (cb, NULL, NULL);
921 buf = xmalloc (buflen);
922 if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
924 /* The translation failed. This is due to an internal
925 host program error, not the target's fault. */
931 if ((s.write_mem) (cb, &s, arg2, buf, buflen) != buflen)
948 result = lstat((char *) t2h_addr(cb, &s, arg1), &statbuf);
953 buflen = cb_host_to_target_stat (cb, NULL, NULL);
954 buf = xmalloc (buflen);
955 if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
957 /* The translation failed. This is due to an internal
958 host program error, not the target's fault. */
964 if ((s.write_mem) (cb, &s, arg2, buf, buflen) != buflen)
981 result = fstat(arg1, &statbuf);
986 buflen = cb_host_to_target_stat (cb, NULL, NULL);
987 buf = xmalloc (buflen);
988 if (cb_host_to_target_stat (cb, &statbuf, buf) != buflen)
990 /* The translation failed. This is due to an internal
991 host program error, not the target's fault. */
997 if ((s.write_mem) (cb, &s, arg2, buf, buflen) != buflen)
1010 struct sysinfo info;
1012 result = sysinfo(&info);
1018 info.uptime = conv_endian(info.uptime);
1019 info.loads[0] = conv_endian(info.loads[0]);
1020 info.loads[1] = conv_endian(info.loads[1]);
1021 info.loads[2] = conv_endian(info.loads[2]);
1022 info.totalram = conv_endian(info.totalram);
1023 info.freeram = conv_endian(info.freeram);
1024 info.sharedram = conv_endian(info.sharedram);
1025 info.bufferram = conv_endian(info.bufferram);
1026 info.totalswap = conv_endian(info.totalswap);
1027 info.freeswap = conv_endian(info.freeswap);
1028 info.procs = conv_endian16(info.procs);
1029 #if LINUX_VERSION_CODE >= 0x20400
1030 info.totalhigh = conv_endian(info.totalhigh);
1031 info.freehigh = conv_endian(info.freehigh);
1032 info.mem_unit = conv_endian(info.mem_unit);
1034 if ((s.write_mem) (cb, &s, arg1, (char *) &info, sizeof(info))
1046 result = ipc(arg1, arg2, arg3, arg4,
1047 (void *) t2h_addr(cb, &s, arg5), arg6);
1054 result = fsync(arg1);
1059 /* utsname contains only arrays of char, so it is not necessary
1060 to translate endian. */
1061 result = uname((struct utsname *) t2h_addr(cb, &s, arg1));
1069 result = adjtimex(&buf);
1075 translate_endian((void *) &buf, sizeof(buf));
1076 if ((s.write_mem) (cb, &s, arg1, (char *) &buf, sizeof(buf))
1086 result = mprotect((void *) arg1, arg2, arg3);
1091 result = fchdir(arg1);
1095 case __NR_setfsuid32:
1097 result = setfsuid(arg1);
1101 case __NR_setfsgid32:
1103 result = setfsgid(arg1);
1112 result = _llseek(arg1, arg2, arg3, &buf, arg5);
1118 translate_endian((void *) &buf, sizeof(buf));
1119 if ((s.write_mem) (cb, &s, t2h_addr(cb, &s, arg4),
1120 (char *) &buf, sizeof(buf)) != sizeof(buf))
1132 result = getdents(arg1, &dir, arg3);
1138 dir.d_ino = conv_endian(dir.d_ino);
1139 dir.d_off = conv_endian(dir.d_off);
1140 dir.d_reclen = conv_endian16(dir.d_reclen);
1141 if ((s.write_mem) (cb, &s, arg2, (char *) &dir, sizeof(dir))
1152 result = flock(arg1, arg2);
1157 result = msync((void *) arg1, arg2, arg3);
1163 struct iovec vector;
1165 vector = *((struct iovec *) t2h_addr(cb, &s, arg2));
1166 translate_endian((void *) &vector, sizeof(vector));
1168 result = readv(arg1, &vector, arg3);
1175 struct iovec vector;
1177 vector = *((struct iovec *) t2h_addr(cb, &s, arg2));
1178 translate_endian((void *) &vector, sizeof(vector));
1180 result = writev(arg1, &vector, arg3);
1185 case __NR_fdatasync:
1186 result = fdatasync(arg1);
1191 result = mlock((void *) t2h_addr(cb, &s, arg1), arg2);
1196 result = munlock((void *) t2h_addr(cb, &s, arg1), arg2);
1200 case __NR_nanosleep:
1202 struct timespec req, rem;
1204 req = *((struct timespec *) t2h_addr(cb, &s, arg2));
1205 translate_endian((void *) &req, sizeof(req));
1207 result = nanosleep(&req, &rem);
1213 translate_endian((void *) &rem, sizeof(rem));
1214 if ((s.write_mem) (cb, &s, arg2, (char *) &rem, sizeof(rem))
1223 case __NR_mremap: /* FIXME */
1224 result = (int) mremap((void *) t2h_addr(cb, &s, arg1), arg2, arg3, arg4);
1228 case __NR_getresuid32:
1229 case __NR_getresuid:
1231 uid_t ruid, euid, suid;
1233 result = getresuid(&ruid, &euid, &suid);
1239 *((uid_t *) t2h_addr(cb, &s, arg1)) = conv_endian(ruid);
1240 *((uid_t *) t2h_addr(cb, &s, arg2)) = conv_endian(euid);
1241 *((uid_t *) t2h_addr(cb, &s, arg3)) = conv_endian(suid);
1249 ufds = *((struct pollfd *) t2h_addr(cb, &s, arg1));
1250 ufds.fd = conv_endian(ufds.fd);
1251 ufds.events = conv_endian16(ufds.events);
1252 ufds.revents = conv_endian16(ufds.revents);
1254 result = poll(&ufds, arg2, arg3);
1259 case __NR_getresgid32:
1260 case __NR_getresgid:
1262 uid_t rgid, egid, sgid;
1264 result = getresgid(&rgid, &egid, &sgid);
1270 *((uid_t *) t2h_addr(cb, &s, arg1)) = conv_endian(rgid);
1271 *((uid_t *) t2h_addr(cb, &s, arg2)) = conv_endian(egid);
1272 *((uid_t *) t2h_addr(cb, &s, arg3)) = conv_endian(sgid);
1277 result = pread(arg1, (void *) t2h_addr(cb, &s, arg2), arg3, arg4);
1282 result = pwrite(arg1, (void *) t2h_addr(cb, &s, arg2), arg3, arg4);
1288 result = chown((char *) t2h_addr(cb, &s, arg1), arg2, arg3);
1293 result = (int) getcwd((char *) t2h_addr(cb, &s, arg1), arg2);
1301 offset = *((off_t *) t2h_addr(cb, &s, arg3));
1302 offset = conv_endian(offset);
1304 result = sendfile(arg1, arg2, &offset, arg3);
1310 *((off_t *) t2h_addr(cb, &s, arg3)) = conv_endian(offset);
1321 m32rbf_h_gr_set (current_cpu, 0, -errcode);
1323 m32rbf_h_gr_set (current_cpu, 0, result);
1327 case TRAP_BREAKPOINT:
1328 sim_engine_halt (sd, current_cpu, NULL, pc,
1329 sim_stopped, SIM_SIGTRAP);
1332 case TRAP_FLUSH_CACHE:
1338 /* Use cr5 as EVB (EIT Vector Base) register. */
1339 USI new_pc = m32rbf_h_cr_get (current_cpu, 5) + 0x40 + num * 4;
1344 /* Fake an "rte" insn. */
1345 /* FIXME: Should duplicate all of rte processing. */
1346 return (pc & -4) + 4;