syscall_emul.hh (11380:3370547fa302) | syscall_emul.hh (11383:5ac090acd180) |
---|---|
1/* 2 * Copyright (c) 2012-2013, 2015 ARM Limited 3 * Copyright (c) 2015 Advanced Micro Devices, Inc. 4 * All rights reserved 5 * 6 * The license below extends only to copyright in the software and shall 7 * not be construed as granting a license to any other intellectual 8 * property including but not limited to intellectual property relating --- 44 unchanged lines hidden (view full) --- 53/// @file syscall_emul.hh 54/// 55/// This file defines objects used to emulate syscalls from the target 56/// application on the host machine. 57 58#ifdef __CYGWIN32__ 59#include <sys/fcntl.h> // for O_BINARY 60#endif | 1/* 2 * Copyright (c) 2012-2013, 2015 ARM Limited 3 * Copyright (c) 2015 Advanced Micro Devices, Inc. 4 * All rights reserved 5 * 6 * The license below extends only to copyright in the software and shall 7 * not be construed as granting a license to any other intellectual 8 * property including but not limited to intellectual property relating --- 44 unchanged lines hidden (view full) --- 53/// @file syscall_emul.hh 54/// 55/// This file defines objects used to emulate syscalls from the target 56/// application on the host machine. 57 58#ifdef __CYGWIN32__ 59#include <sys/fcntl.h> // for O_BINARY 60#endif |
61#include <sys/mman.h> |
|
61#include <sys/stat.h> 62#include <sys/time.h> 63#include <sys/uio.h> 64#include <fcntl.h> 65 66#include <cerrno> 67#include <string> 68 --- 1150 unchanged lines hidden (view full) --- 1219 if (result < 0) 1220 return -errno; 1221 1222 return result; 1223} 1224 1225 1226/// Target mmap() handler. | 62#include <sys/stat.h> 63#include <sys/time.h> 64#include <sys/uio.h> 65#include <fcntl.h> 66 67#include <cerrno> 68#include <string> 69 --- 1150 unchanged lines hidden (view full) --- 1220 if (result < 0) 1221 return -errno; 1222 1223 return result; 1224} 1225 1226 1227/// Target mmap() handler. |
1227/// 1228/// We don't really handle mmap(). If the target is mmaping an 1229/// anonymous region or /dev/zero, we can get away with doing basically 1230/// nothing (since memory is initialized to zero and the simulator 1231/// doesn't really check addresses anyway). 1232/// | |
1233template <class OS> 1234SyscallReturn 1235mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1236{ 1237 int index = 0; 1238 Addr start = p->getSyscallArg(tc, index); 1239 uint64_t length = p->getSyscallArg(tc, index); | 1228template <class OS> 1229SyscallReturn 1230mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 1231{ 1232 int index = 0; 1233 Addr start = p->getSyscallArg(tc, index); 1234 uint64_t length = p->getSyscallArg(tc, index); |
1240 index++; // int prot = p->getSyscallArg(tc, index); 1241 int flags = p->getSyscallArg(tc, index); | 1235 int prot = p->getSyscallArg(tc, index); 1236 int tgt_flags = p->getSyscallArg(tc, index); |
1242 int tgt_fd = p->getSyscallArg(tc, index); 1243 int offset = p->getSyscallArg(tc, index); 1244 | 1237 int tgt_fd = p->getSyscallArg(tc, index); 1238 int offset = p->getSyscallArg(tc, index); 1239 |
1245 if (length > 0x100000000ULL) 1246 warn("mmap length argument %#x is unreasonably large.\n", length); | 1240 DPRINTF_SYSCALL(Verbose, "mmap(0x%x, len %d, prot %d, flags %d, fd %d, " 1241 "offs %d)\n", start, length, prot, tgt_flags, tgt_fd, 1242 offset); |
1247 | 1243 |
1248 if (!(flags & OS::TGT_MAP_ANONYMOUS)) { 1249 FDEntry *fde = p->getFDEntry(tgt_fd); 1250 if (!fde || fde->fd < 0) { 1251 warn("mmap failing: target fd %d is not valid\n", tgt_fd); 1252 return -EBADF; 1253 } | 1244 if (start & (TheISA::PageBytes - 1) || 1245 offset & (TheISA::PageBytes - 1) || 1246 (tgt_flags & OS::TGT_MAP_PRIVATE && 1247 tgt_flags & OS::TGT_MAP_SHARED) || 1248 (!(tgt_flags & OS::TGT_MAP_PRIVATE) && 1249 !(tgt_flags & OS::TGT_MAP_SHARED)) || 1250 !length) { 1251 return -EINVAL; 1252 } |
1254 | 1253 |
1255 if (fde->filename != "/dev/zero") { 1256 // This is very likely broken, but leave a warning here 1257 // (rather than panic) in case /dev/zero is known by 1258 // another name on some platform 1259 warn("allowing mmap of file %s; mmap not supported on files" 1260 " other than /dev/zero\n", fde->filename); 1261 } | 1254 if ((prot & PROT_WRITE) && (tgt_flags & OS::TGT_MAP_SHARED)) { 1255 // With shared mmaps, there are two cases to consider: 1256 // 1) anonymous: writes should modify the mapping and this should be 1257 // visible to observers who share the mapping. Currently, it's 1258 // difficult to update the shared mapping because there's no 1259 // structure which maintains information about the which virtual 1260 // memory areas are shared. If that structure existed, it would be 1261 // possible to make the translations point to the same frames. 1262 // 2) file-backed: writes should modify the mapping and the file 1263 // which is backed by the mapping. The shared mapping problem is the 1264 // same as what was mentioned about the anonymous mappings. For 1265 // file-backed mappings, the writes to the file are difficult 1266 // because it requires syncing what the mapping holds with the file 1267 // that resides on the host system. So, any write on a real system 1268 // would cause the change to be propagated to the file mapping at 1269 // some point in the future (the inode is tracked along with the 1270 // mapping). This isn't guaranteed to always happen, but it usually 1271 // works well enough. The guarantee is provided by the msync system 1272 // call. We could force the change through with shared mappings with 1273 // a call to msync, but that again would require more information 1274 // than we currently maintain. 1275 warn("mmap: writing to shared mmap region is currently " 1276 "unsupported. The write succeeds on the target, but it " 1277 "will not be propagated to the host or shared mappings"); |
1262 } 1263 1264 length = roundUp(length, TheISA::PageBytes); 1265 | 1278 } 1279 1280 length = roundUp(length, TheISA::PageBytes); 1281 |
1266 if ((start % TheISA::PageBytes) != 0 || 1267 (offset % TheISA::PageBytes) != 0) { 1268 warn("mmap failing: arguments not page-aligned: " 1269 "start 0x%x offset 0x%x", 1270 start, offset); 1271 return -EINVAL; 1272 } | 1282 int sim_fd = -1; 1283 uint8_t *pmap = nullptr; 1284 if (!(tgt_flags & OS::TGT_MAP_ANONYMOUS)) { 1285 sim_fd = p->getSimFD(tgt_fd); 1286 if (sim_fd < 0) 1287 return -EBADF; |
1273 | 1288 |
1274 // are we ok with clobbering existing mappings? only set this to 1275 // true if the user has been warned. 1276 bool clobber = false; | 1289 pmap = (decltype(pmap))mmap(NULL, length, PROT_READ, MAP_PRIVATE, 1290 sim_fd, offset); |
1277 | 1291 |
1278 // try to use the caller-provided address if there is one 1279 bool use_provided_address = (start != 0); 1280 1281 if (use_provided_address) { 1282 // check to see if the desired address is already in use 1283 if (!p->pTable->isUnmapped(start, length)) { 1284 // there are existing mappings in the desired range 1285 // whether we clobber them or not depends on whether the caller 1286 // specified MAP_FIXED 1287 if (flags & OS::TGT_MAP_FIXED) { 1288 // MAP_FIXED specified: map attempt fails 1289 return -EINVAL; 1290 } else { 1291 // MAP_FIXED not specified: ignore suggested start address 1292 warn("mmap: ignoring suggested map address 0x%x\n", start); 1293 use_provided_address = false; 1294 } | 1292 if (pmap == (decltype(pmap))-1) { 1293 warn("mmap: failed to map file into host address space"); 1294 return -errno; |
1295 } 1296 } 1297 | 1295 } 1296 } 1297 |
1298 if (!use_provided_address) { 1299 // no address provided, or provided address unusable: 1300 // pick next address from our "mmap region" 1301 if (OS::mmapGrowsDown()) { 1302 start = p->mmap_end - length; 1303 p->mmap_end = start; 1304 } else { 1305 start = p->mmap_end; 1306 p->mmap_end += length; | 1298 // Extend global mmap region if necessary. Note that we ignore the 1299 // start address unless MAP_FIXED is specified. 1300 if (!(tgt_flags & OS::TGT_MAP_FIXED)) { 1301 start = (OS::mmapGrowsDown()) ? p->mmap_end - length : p->mmap_end; 1302 p->mmap_end = (OS::mmapGrowsDown()) ? start : p->mmap_end + length; 1303 } 1304 1305 DPRINTF_SYSCALL(Verbose, " mmap range is 0x%x - 0x%x\n", 1306 start, start + length - 1); 1307 1308 // We only allow mappings to overwrite existing mappings if 1309 // TGT_MAP_FIXED is set. Otherwise it shouldn't be a problem 1310 // because we ignore the start hint if TGT_MAP_FIXED is not set. 1311 int clobber = tgt_flags & OS::TGT_MAP_FIXED; 1312 if (clobber) { 1313 for (auto tc : p->system->threadContexts) { 1314 // If we might be overwriting old mappings, we need to 1315 // invalidate potentially stale mappings out of the TLBs. 1316 tc->getDTBPtr()->flushAll(); 1317 tc->getITBPtr()->flushAll(); |
1307 } 1308 } 1309 | 1318 } 1319 } 1320 |
1321 // Allocate physical memory and map it in. If the page table is already 1322 // mapped and clobber is not set, the simulator will issue throw a 1323 // fatal and bail out of the simulation. |
|
1310 p->allocateMem(start, length, clobber); 1311 | 1324 p->allocateMem(start, length, clobber); 1325 |
1326 // Transfer content into target address space. 1327 SETranslatingPortProxy &tp = tc->getMemProxy(); 1328 if (tgt_flags & OS::TGT_MAP_ANONYMOUS) { 1329 // In general, we should zero the mapped area for anonymous mappings, 1330 // with something like: 1331 // tp.memsetBlob(start, 0, length); 1332 // However, given that we don't support sparse mappings, and 1333 // some applications can map a couple of gigabytes of space 1334 // (intending sparse usage), that can get painfully expensive. 1335 // Fortunately, since we don't properly implement munmap either, 1336 // there's no danger of remapping used memory, so for now all 1337 // newly mapped memory should already be zeroed so we can skip it. 1338 } else { 1339 // It is possible to mmap an area larger than a file, however 1340 // accessing unmapped portions the system triggers a "Bus error" 1341 // on the host. We must know when to stop copying the file from 1342 // the host into the target address space. 1343 struct stat file_stat; 1344 if (fstat(sim_fd, &file_stat) > 0) 1345 fatal("mmap: cannot stat file"); 1346 1347 // Copy the portion of the file that is resident. This requires 1348 // checking both the mmap size and the filesize that we are 1349 // trying to mmap into this space; the mmap size also depends 1350 // on the specified offset into the file. 1351 uint64_t size = std::min((uint64_t)file_stat.st_size - offset, 1352 length); 1353 tp.writeBlob(start, pmap, size); 1354 1355 // Cleanup the mmap region before exiting this function. 1356 munmap(pmap, length); 1357 1358 // Note that we do not zero out the remainder of the mapping. This 1359 // is done by a real system, but it probably will not affect 1360 // execution (hopefully). 1361 } 1362 |
|
1312 return start; 1313} 1314 1315/// Target getrlimit() handler. 1316template <class OS> 1317SyscallReturn 1318getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1319 ThreadContext *tc) --- 222 unchanged lines hidden --- | 1363 return start; 1364} 1365 1366/// Target getrlimit() handler. 1367template <class OS> 1368SyscallReturn 1369getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 1370 ThreadContext *tc) --- 222 unchanged lines hidden --- |