diff options
author | Hans-Peter Nilsson <hp@axis.com> | 2008-12-30 13:36:17 +0000 |
---|---|---|
committer | Hans-Peter Nilsson <hp@axis.com> | 2008-12-30 13:36:17 +0000 |
commit | c06ccdf1b680092e01cba0af3681c12bf63d2ed0 (patch) | |
tree | d6053061550744b4099c5c24e0a3fbf6f0d5f5f8 /sim/cris/traps.c | |
parent | 80e5c09e9d1ee8375324c98d40841b572896f82e (diff) | |
download | gdb-c06ccdf1b680092e01cba0af3681c12bf63d2ed0.zip gdb-c06ccdf1b680092e01cba0af3681c12bf63d2ed0.tar.gz gdb-c06ccdf1b680092e01cba0af3681c12bf63d2ed0.tar.bz2 |
* 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.
Diffstat (limited to 'sim/cris/traps.c')
-rw-r--r-- | sim/cris/traps.c | 195 |
1 files changed, 176 insertions, 19 deletions
diff --git a/sim/cris/traps.c b/sim/cris/traps.c index 05c364e..044d6c6 100644 --- a/sim/cris/traps.c +++ b/sim/cris/traps.c @@ -87,6 +87,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ #define TARGET_SYS_uname 122 #define TARGET_SYS_mprotect 125 #define TARGET_SYS_llseek 140 +#define TARGET_SYS_writev 146 #define TARGET_SYS__sysctl 149 #define TARGET_SYS_sched_setparam 154 #define TARGET_SYS_sched_getparam 155 @@ -912,6 +913,57 @@ is_mapped (SIM_DESC sd ATTRIBUTE_UNUSED, 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. */ static USI @@ -1617,12 +1669,23 @@ cris_break_13_handler (SIM_CPU *current_cpu, USI callnum, USI arg1, != (TARGET_PROT_READ | TARGET_PROT_WRITE | TARGET_PROT_EXEC)) + && (prot != (TARGET_PROT_READ | TARGET_PROT_EXEC)) && prot != TARGET_PROT_READ) || (flags != (TARGET_MAP_ANONYMOUS | 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) - || (fd != (USI) -1 && prot != TARGET_PROT_READ) - || pgoff != 0) + || (fd != (USI) -1 + && 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, ¤t_cpu->highest_mmapped_page, + addr, (len + 8191) & ~8191))) { retval = 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. */ USI newlen = (len + 8191) & ~8191; - /* We only support read, which we should already have - checked. Check again anyway. */ - if (prot != TARGET_PROT_READ) + /* We only support read, read|exec, and read|write, + which we should already have checked. Check again + 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, ¤t_cpu->highest_mmapped_page, + addr, newlen) != 0) abort (); newaddr @@ -1663,6 +1734,16 @@ cris_break_13_handler (SIM_CPU *current_cpu, USI callnum, USI arg1, break; } + /* We were asked for MAP_FIXED, but couldn't. */ + if ((flags & TARGET_MAP_FIXED) && newaddr != addr) + { + abort (); + unmap_pages (sd, ¤t_cpu->highest_mmapped_page, + newaddr, newlen); + retval = -cb_host_to_target_errno (cb, EINVAL); + break; + } + /* Find the current position in the file. */ s.func = TARGET_SYS_lseek; s.arg1 = fd; @@ -1675,6 +1756,17 @@ cris_break_13_handler (SIM_CPU *current_cpu, USI callnum, USI arg1, 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) + abort (); + /* Use the standard read callback to read in "len" bytes. */ s.func = TARGET_SYS_read; @@ -1702,31 +1794,47 @@ cris_break_13_handler (SIM_CPU *current_cpu, USI callnum, USI arg1, } else { - USI newaddr - = create_map (sd, ¤t_cpu->highest_mmapped_page, addr, - (len + 8191) & ~8191); + USI newlen = (len + 8191) & ~8191; + USI newaddr; + + if ((flags & TARGET_MAP_FIXED) + && unmap_pages (sd, ¤t_cpu->highest_mmapped_page, + addr, newlen) != 0) + abort (); + + newaddr = create_map (sd, ¤t_cpu->highest_mmapped_page, addr, + newlen); if (newaddr >= (USI) -8191) retval = -cb_host_to_target_errno (cb, -(SI) newaddr); else retval = newaddr; + + if ((flags & TARGET_MAP_FIXED) && newaddr != addr) + { + abort (); + unmap_pages (sd, ¤t_cpu->highest_mmapped_page, + newaddr, newlen); + retval = -cb_host_to_target_errno (cb, EINVAL); + break; + } } break; } case TARGET_SYS_mprotect: { - /* We only cover the case of linuxthreads mprotecting out its - stack guard page. */ + /* We only cover the case of linuxthreads mprotecting out + 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 len = arg2; USI prot = arg3; - if ((addr & 8191) != 0 - || len != 8192 - || prot != TARGET_PROT_NONE - || !is_mapped (sd, ¤t_cpu->highest_mmapped_page, addr, - len)) + if (prot != TARGET_PROT_NONE + || !is_mapped_only (sd, ¤t_cpu->highest_mmapped_page, + addr, (len + 8191) & ~8191)) { retval = cris_unknown_syscall (current_cpu, pc, @@ -1738,10 +1846,10 @@ cris_break_13_handler (SIM_CPU *current_cpu, USI callnum, USI arg1, break; } - /* FIXME: We should account for pages like this that are - "mprotected out". For now, we just tell the simulator - core to remove that page from its map. */ - sim_core_detach (sd, NULL, 0, 0, addr); + /* Just ignore this. We could make this equal to munmap, + but then we'd have to make sure no anon mmaps gets this + address before a subsequent MAP_FIXED mmap intended to + override it. */ retval = 0; break; } @@ -2171,6 +2279,55 @@ cris_break_13_handler (SIM_CPU *current_cpu, USI callnum, USI arg1, 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 of this writing, cb_syscall does not have code for it, and we need target-specific code for the threads implementation |