* cris/traps.c (TARGET_SYS_writev): New macro.

(is_mapped_only, cris_dump_map): New functions.
	(cris_break_13_handler) <case TARGET_SYS_mmap2>: Handle more flags
	and prot combinations and a non-zero page-offset.  If
	TARGET_MAP_FIXED, unmap pages before mapping them.
	<case TARGET_SYS_mprotect>: When checking, allow any length
	argument.  Don't actually do anything.
	<case TARGET_SYS_writev>: New case.
This commit is contained in:
Hans-Peter Nilsson
2008-12-30 13:36:17 +00:00
parent 80e5c09e9d
commit c06ccdf1b6
2 changed files with 185 additions and 19 deletions

@ -1,5 +1,14 @@
2008-12-30 Hans-Peter Nilsson <hp@axis.com> 2008-12-30 Hans-Peter Nilsson <hp@axis.com>
* cris/traps.c (TARGET_SYS_writev): New macro.
(is_mapped_only, cris_dump_map): New functions.
(cris_break_13_handler) <case TARGET_SYS_mmap2>: Handle more flags
and prot combinations and a non-zero page-offset. If
TARGET_MAP_FIXED, unmap pages before mapping them.
<case TARGET_SYS_mprotect>: When checking, allow any length
argument. Don't actually do anything.
<case TARGET_SYS_writev>: New case.
* cris/Makefile.in (SIM_OBJS): Remove sim-hload.o. * cris/Makefile.in (SIM_OBJS): Remove sim-hload.o.
* cris/sim-if.c: Include elf-bfd.h. * cris/sim-if.c: Include elf-bfd.h.
(struct progbounds): New members end_loadmem, start_nonloadmem. (struct progbounds): New members end_loadmem, start_nonloadmem.

@ -87,6 +87,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#define TARGET_SYS_uname 122 #define TARGET_SYS_uname 122
#define TARGET_SYS_mprotect 125 #define TARGET_SYS_mprotect 125
#define TARGET_SYS_llseek 140 #define TARGET_SYS_llseek 140
#define TARGET_SYS_writev 146
#define TARGET_SYS__sysctl 149 #define TARGET_SYS__sysctl 149
#define TARGET_SYS_sched_setparam 154 #define TARGET_SYS_sched_setparam 154
#define TARGET_SYS_sched_getparam 155 #define TARGET_SYS_sched_getparam 155
@ -912,6 +913,57 @@ is_mapped (SIM_DESC sd ATTRIBUTE_UNUSED,
return 0; return 0;
} }
/* Check whether any part of [addr .. addr + len - 1] is *un*mapped.
Return 1 if the whole area is mapped, 0 otherwise. */
static USI
is_mapped_only (SIM_DESC sd ATTRIBUTE_UNUSED,
struct cris_sim_mmapped_page **rootp,
USI addr, USI len)
{
struct cris_sim_mmapped_page *mapp;
if (len == 0 || (len & 8191))
abort ();
/* Iterate over the reverse-address sorted pages until we find a page
lower than the checked area. */
for (mapp = *rootp; mapp != NULL && mapp->addr >= addr; mapp = mapp->prev)
if (addr == mapp->addr && len == 8192)
return 1;
else if (addr + len > mapp->addr)
len -= 8192;
return 0;
}
/* Debug helper; to be run from gdb. */
void
cris_dump_map (SIM_CPU *current_cpu)
{
struct cris_sim_mmapped_page *mapp;
USI start, end;
for (mapp = current_cpu->highest_mmapped_page,
start = mapp == NULL ? 0 : mapp->addr + 8192,
end = mapp == NULL ? 0 : mapp->addr + 8191;
mapp != NULL;
mapp = mapp->prev)
{
if (mapp->addr != start - 8192)
{
sim_io_eprintf (CPU_STATE (current_cpu), "0x%x..0x%x\n", start, end);
end = mapp->addr + 8191;
}
start = mapp->addr;
}
if (current_cpu->highest_mmapped_page != NULL)
sim_io_eprintf (CPU_STATE (current_cpu), "0x%x..0x%x\n", start, end);
}
/* Create mmapped memory. */ /* Create mmapped memory. */
static USI static USI
@ -1617,12 +1669,23 @@ cris_break_13_handler (SIM_CPU *current_cpu, USI callnum, USI arg1,
!= (TARGET_PROT_READ != (TARGET_PROT_READ
| TARGET_PROT_WRITE | TARGET_PROT_WRITE
| TARGET_PROT_EXEC)) | TARGET_PROT_EXEC))
&& (prot != (TARGET_PROT_READ | TARGET_PROT_EXEC))
&& prot != TARGET_PROT_READ) && prot != TARGET_PROT_READ)
|| (flags != (TARGET_MAP_ANONYMOUS | TARGET_MAP_PRIVATE) || (flags != (TARGET_MAP_ANONYMOUS | TARGET_MAP_PRIVATE)
&& flags != TARGET_MAP_PRIVATE && flags != TARGET_MAP_PRIVATE
&& flags != (TARGET_MAP_ANONYMOUS
| TARGET_MAP_PRIVATE | TARGET_MAP_FIXED)
&& flags != (TARGET_MAP_PRIVATE | TARGET_MAP_FIXED)
&& flags != TARGET_MAP_SHARED) && flags != TARGET_MAP_SHARED)
|| (fd != (USI) -1 && prot != TARGET_PROT_READ) || (fd != (USI) -1
|| pgoff != 0) && prot != TARGET_PROT_READ
&& prot != (TARGET_PROT_READ | TARGET_PROT_EXEC)
&& prot != (TARGET_PROT_READ | TARGET_PROT_WRITE))
|| (fd == (USI) -1 && pgoff != 0)
|| (fd != (USI) -1 && (flags & TARGET_MAP_ANONYMOUS))
|| ((flags & TARGET_MAP_FIXED) == 0
&& is_mapped (sd, &current_cpu->highest_mmapped_page,
addr, (len + 8191) & ~8191)))
{ {
retval retval
= cris_unknown_syscall (current_cpu, pc, = cris_unknown_syscall (current_cpu, pc,
@ -1647,9 +1710,17 @@ cris_break_13_handler (SIM_CPU *current_cpu, USI callnum, USI arg1,
/* A non-aligned argument is allowed for files. */ /* A non-aligned argument is allowed for files. */
USI newlen = (len + 8191) & ~8191; USI newlen = (len + 8191) & ~8191;
/* We only support read, which we should already have /* We only support read, read|exec, and read|write,
checked. Check again anyway. */ which we should already have checked. Check again
if (prot != TARGET_PROT_READ) anyway. */
if (prot != TARGET_PROT_READ
&& prot != (TARGET_PROT_READ | TARGET_PROT_EXEC)
&& prot != (TARGET_PROT_READ | TARGET_PROT_WRITE))
abort ();
if ((flags & TARGET_MAP_FIXED)
&& unmap_pages (sd, &current_cpu->highest_mmapped_page,
addr, newlen) != 0)
abort (); abort ();
newaddr newaddr
@ -1663,6 +1734,16 @@ cris_break_13_handler (SIM_CPU *current_cpu, USI callnum, USI arg1,
break; break;
} }
/* We were asked for MAP_FIXED, but couldn't. */
if ((flags & TARGET_MAP_FIXED) && newaddr != addr)
{
abort ();
unmap_pages (sd, &current_cpu->highest_mmapped_page,
newaddr, newlen);
retval = -cb_host_to_target_errno (cb, EINVAL);
break;
}
/* Find the current position in the file. */ /* Find the current position in the file. */
s.func = TARGET_SYS_lseek; s.func = TARGET_SYS_lseek;
s.arg1 = fd; s.arg1 = fd;
@ -1672,6 +1753,17 @@ cris_break_13_handler (SIM_CPU *current_cpu, USI callnum, USI arg1,
abort (); abort ();
pos = s.result; pos = s.result;
if (s.result < 0)
abort ();
/* Move to the correct offset in the file. */
s.func = TARGET_SYS_lseek;
s.arg1 = fd;
s.arg2 = pgoff*8192;
s.arg3 = SEEK_SET;
if (cb_syscall (cb, &s) != CB_RC_OK)
abort ();
if (s.result < 0) if (s.result < 0)
abort (); abort ();
@ -1702,31 +1794,47 @@ cris_break_13_handler (SIM_CPU *current_cpu, USI callnum, USI arg1,
} }
else else
{ {
USI newaddr USI newlen = (len + 8191) & ~8191;
= create_map (sd, &current_cpu->highest_mmapped_page, addr, USI newaddr;
(len + 8191) & ~8191);
if ((flags & TARGET_MAP_FIXED)
&& unmap_pages (sd, &current_cpu->highest_mmapped_page,
addr, newlen) != 0)
abort ();
newaddr = create_map (sd, &current_cpu->highest_mmapped_page, addr,
newlen);
if (newaddr >= (USI) -8191) if (newaddr >= (USI) -8191)
retval = -cb_host_to_target_errno (cb, -(SI) newaddr); retval = -cb_host_to_target_errno (cb, -(SI) newaddr);
else else
retval = newaddr; retval = newaddr;
if ((flags & TARGET_MAP_FIXED) && newaddr != addr)
{
abort ();
unmap_pages (sd, &current_cpu->highest_mmapped_page,
newaddr, newlen);
retval = -cb_host_to_target_errno (cb, EINVAL);
break;
}
} }
break; break;
} }
case TARGET_SYS_mprotect: case TARGET_SYS_mprotect:
{ {
/* We only cover the case of linuxthreads mprotecting out its /* We only cover the case of linuxthreads mprotecting out
stack guard page. */ its stack guard page and of dynamic loading mprotecting
away the data (for some reason the whole library, then
mprotects away the data part and mmap-FIX:es it again. */
USI addr = arg1; USI addr = arg1;
USI len = arg2; USI len = arg2;
USI prot = arg3; USI prot = arg3;
if ((addr & 8191) != 0 if (prot != TARGET_PROT_NONE
|| len != 8192 || !is_mapped_only (sd, &current_cpu->highest_mmapped_page,
|| prot != TARGET_PROT_NONE addr, (len + 8191) & ~8191))
|| !is_mapped (sd, &current_cpu->highest_mmapped_page, addr,
len))
{ {
retval retval
= cris_unknown_syscall (current_cpu, pc, = cris_unknown_syscall (current_cpu, pc,
@ -1738,10 +1846,10 @@ cris_break_13_handler (SIM_CPU *current_cpu, USI callnum, USI arg1,
break; break;
} }
/* FIXME: We should account for pages like this that are /* Just ignore this. We could make this equal to munmap,
"mprotected out". For now, we just tell the simulator but then we'd have to make sure no anon mmaps gets this
core to remove that page from its map. */ address before a subsequent MAP_FIXED mmap intended to
sim_core_detach (sd, NULL, 0, 0, addr); override it. */
retval = 0; retval = 0;
break; break;
} }
@ -2171,6 +2279,55 @@ cris_break_13_handler (SIM_CPU *current_cpu, USI callnum, USI arg1,
break; break;
} }
/* ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
where:
struct iovec {
void *iov_base; Starting address
size_t iov_len; Number of bytes to transfer
}; */
case TARGET_SYS_writev:
{
SI fd = arg1;
SI iov = arg2;
SI iovcnt = arg3;
SI retcnt = 0;
int i;
/* We'll ignore strict error-handling and just do multiple write calls. */
for (i = 0; i < iovcnt; i++)
{
int sysret;
USI iov_base
= sim_core_read_unaligned_4 (current_cpu, pc, 0,
iov + 8*i);
USI iov_len
= sim_core_read_unaligned_4 (current_cpu, pc, 0,
iov + 8*i + 4);
s.func = TARGET_SYS_write;
s.arg1 = fd;
s.arg2 = iov_base;
s.arg3 = iov_len;
if (cb_syscall (cb, &s) != CB_RC_OK)
abort ();
sysret = s.result == -1 ? -s.errcode : s.result;
if (sysret != iov_len)
{
if (i != 0)
abort ();
retcnt = sysret;
break;
}
retcnt += iov_len;
}
retval = retcnt;
}
break;
/* This one does have a generic callback function, but at the time /* This one does have a generic callback function, but at the time
of this writing, cb_syscall does not have code for it, and we of this writing, cb_syscall does not have code for it, and we
need target-specific code for the threads implementation need target-specific code for the threads implementation