sim-se: add a faux-filesystem

This change introduces the concept of a faux-filesystem.
The faux-filesystem creates a directory structure in m5out
(or whatever output dir the user specifies) where system calls
may be redirected.

This is useful to avoid non-determinism when reading files
with varying path names (e.g., variations from run-to-run if
the simulation is scheduled on a cluster where paths may change).

Also, this changeset allows circumventing host pseudofiles which
have information specific to the host processor (such as cache
hierarchy or processor information). Bypassing host pseudofiles
can be useful when executing runtimes in the absence of an
operating system kernel since runtimes may try to query standard
files (i.e. /proc or /sys) which are not relevant to an
application executing in syscall emulation mode.

Change-Id: I90821b3b403168b904a662fa98b85def1628621c
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/12119
Reviewed-by: Jason Lowe-Power <jason@lowepower.com>
Maintainer: Jason Lowe-Power <jason@lowepower.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
David Hashe
2018-04-18 16:36:55 -04:00
committed by Brandon Potter
parent e8d0b755ea
commit 54c77aa055
17 changed files with 755 additions and 94 deletions

153
src/doc/se-files.txt Normal file
View File

@@ -0,0 +1,153 @@
Copyright (c) 2015-Present Advanced Micro Devices, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met: redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer;
redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution;
neither the name of the copyright holders nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Authors: Brandon Potter
===============================================================================
This file exists to educate users and notify them that some filesystem open
system calls may have been redirected by system call emulation mode
(henceforth se-mode).
To provide background, system calls to open files with SYS_OPEN (man 2 open)
inside se-mode will resolve by pass-through to glibc calls (man 3 open) on the
host machine. The host machine will open the file on behalf of the simulator.
Subsequently, se-mode acts as a shim for file access to the opened file. By
utilizing the host machine, se-mode gains quite a bit of utility without
needing to implement an actual filesystem.
A scenario for using normal files might be `/bin/cat $HOME/my_data_file`
as the simulated application (and option). The simulator leverages the host
file system to provide access to my_data_file in this case. Several things
happen inside the simulator:
1) The cat command will open $HOME/my_data_file by invoking the open
system call (SYS_OPEN). In se-mode, SYS_OPEN is trapped by the simulator and
the syscall_emul.hh:openImpl implementation is provided as a drop-in
replacement for what normally occurs inside a real operating system.
2) The openImpl code will pass through several path checks and realize
that the file needs to be handled in the 'normal' case where se-mode utilizes
the host filesystem.
3) The openImpl code will use the glibc open library call on
$HOME/my_data_file after normalizing invocation options.
4) If the file successfully opens, se-mode will record the file descriptor
returned from the glibc open and provide a translated file descriptor to the
application. (If the glibc's file descriptor was passed back to the
application, it would be noticable that the application runtime environment
was wonky. The gem5.{opt,debug,fast} process needs to open files for its own
purposes and the file descriptors for the simulated application perspective
would appear out-of-order and arbitrary. They should appear in-order with the
lowest available file-desciptor assigned on calls to SYS_OPEN. So, se-mode
adds a level of indirection to resolve this problem.)
However, there are files which users might not want to open on the host
machine; providing file access and/or file visibility to the simulated
application may not make sense in these cases. Historically, these files
have been handled by os-specific code in se-mode. The os-specific
implementation has been referred to as 'special files'. Examples of
special file implementations include /proc/meminfo and /etc/passwd. (See
src/kern/linux/linux.cc for more details.)
A scenario for using special files might be running `/bin/cat /proc/meminfo`
as the simulated application (and option). Several things will happen inside
the simulator:
1) The cat command will open the /proc/meminfo file by invoking the open
system call (SYS_OPEN). In se-mode, SYS_OPEN is trapped by the simulator and
the syscall_emul.hh:openImpl implementation is provided as a drop-in
replacement for what normally occurs inside a real operating system.
2) The openImpl code checks to see if /proc/meminfo matches a special
file. When it notices the match, it invokes code to generate a replacement
file rather than open the file on the host machine. (As it turns out, opening
the host's version of /proc/meminfo will resolve to the gem5 executable which
is probably not what the application intended.)
3) The generated file is provided a file descriptor (which itself has
special handling to preserve the illusion that the application is not running
inside a simulator under weird conditions). The file descriptor is passed
back to the application and it can subsequently use the file descriptor to
access the redirected /proc/meminfo file.
Regarding special files, a subtle but important point is that these files
are generated dynamically during simulation (in C++ code). Certain files,
such as /proc/meminfo depend on the application state inside the simulator to
have valid contents. With some files, you generally cannot anticipate what
file contents should be before the application actually tries to inspect the
contents. These types of files should all be handled using the special files
method.
As an aside, users might also want to restrict the contents of a file to
prevent non-determinism in the simulation. (This is another case for special
handling of files.) It can be annoying to try to generate statistics for your
new hardware widget (which of course will improve performance by some
non-trivial percentage) when variance in the statistics is caused by
randomness of file contents. A specific example which comes to mind is
reading the contents of /dev/random. Ideally, se-mode should introduce no
non-determinism. However, that is difficult (if not impossible) to achieve in
practice for every application thrown at the simulator.
In addition to special files, there is another method to handle filesystem
redirection. Instead of dynamically generating a file and providing it to
the application, it is possible to pregenerate files on the host filesystem
and redirect open calls to the pregenerated files. This is achieved by
capturing the paths provided by the application SYS_OPEN and modifying the
path before issuing the pass-through call to the host filesystem glibc open.
The name for this feature is 'faux filesystem' (henceforth faux-fs).
With faux-fs, users can add paths via command line (via --chroot) or by
modifying their configuration file to use the RedirectPath class. These
paths take the form of original_path-->set_of_modified_paths. For instance,
/proc/cpuinfo might be redirected to /usr/local/gem5_fs/cpuinfo __OR__
/home/me/gem5_folder/cpuinfo __OR__ /nonsensical_name/foo_bar, etc.. The
matching pattern and directory/file-structure is controlled by the user. The
pattern match hits on the first available file which actually exists on the
host machine.
As another subtle point, the faux-fs handling is fixed at simulator
configuration time. The path redirection becomes static after configuration
and the Python generated files in simout/fs/.. also exist after configuration.
The faux-fs mechanism is __NOT__ suitable for files such a /proc/meminfo
since those types of files rely on runtime application characteristics.
Currently, faux-fs is setup to create a few files on behalf of the average
user. These files are all stuffed into the simout directory under a 'fs'
folder. By default, the path is $gem5_dir/m5out/fs. These files are all
hardcoded in the configuration since it is unlikely that an application wants
to see the host version of the files. At the time of writing, the list can be
viewed in configs/example/se.py by searching for RedirectPath. Most of
the faux-fs Python generated files depend on simulator configuration (i.e.
number of cores, caches, nodes, etc..). Sophisiticated runtimes might query
these files for hardware information in certain applications (i.e.
applications using MPI or ROCm since these runtimes utilize libnuma.so).
Of note, dynamically executables will open shared object files in the same
manner as normal files. It is possible and maybe enen preferential to utilize
the faux-fs to create a platform independent way of running applications in
se-mode. Users can stuff all the shared libraries into a folder and commit the
folder as part of their repository state. The chroot option can be made to
point to the shared library folder (for each library) and these libraries will
be redirected away from host libraries. This can help to alleviate environment
problems between machines.
If there is any confusion on path redirection, the system call debug traces
can be used to emit information regarding path redirection.

View File

@@ -88,7 +88,7 @@ std::string
Linux::etcPasswd(Process *process, ThreadContext *tc)
{
return csprintf("gem5-user:x:1000:1000:gem5-user,,,:%s:/bin/bash\n",
process->getcwd());
process->tgtCwd);
}
std::string

View File

@@ -29,6 +29,7 @@
from m5.SimObject import *
from m5.params import *
from m5.proxy import *
from os import getcwd
class Process(SimObject):
type = 'Process'
@@ -58,7 +59,7 @@ class Process(SimObject):
executable = Param.String('', "executable (overrides cmd[0] if set)")
cmd = VectorParam.String("command line (executable plus arguments)")
env = VectorParam.String([], "environment settings")
cwd = Param.String('', "current working directory")
cwd = Param.String(getcwd(), "current working directory")
simpoint = Param.UInt64(0, 'simulation point at which to start simulation')
drivers = VectorParam.EmulatedDriver([], 'Available emulated drivers')

43
src/sim/RedirectPath.py Normal file
View File

@@ -0,0 +1,43 @@
# Copyright (c) 2015 Advanced Micro Devices, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: David Hashe
from m5.SimObject import SimObject
from m5.params import *
from m5.proxy import *
class RedirectPath(SimObject):
""" Stores paths for filesystem redirection during syscalls. If a path
matches 'appPath', then the syscall is redirected to the first 'hostPath'
that contains the non-overlapping portion of the path as a valid file. If
there are no hits, then the syscall is redirected to the first value.
"""
type = 'RedirectPath'
cxx_header = "sim/redirect_path.hh"
app_path = Param.String("/", "filesystem path from an app's perspective")
host_paths = VectorParam.String(["/"], "file path on host filesystem")

View File

@@ -38,6 +38,7 @@ SimObject('VoltageDomain.py')
SimObject('System.py')
SimObject('DVFSHandler.py')
SimObject('SubSystem.py')
SimObject('RedirectPath.py')
Source('arguments.cc')
Source('async.cc')
@@ -56,6 +57,7 @@ Source('init_signals.cc')
Source('main.cc', tags='main')
Source('port.cc')
Source('python.cc', add_tags='python')
Source('redirect_path.cc')
Source('root.cc')
Source('serialize.cc')
Source('drain.cc')

View File

@@ -83,6 +83,8 @@ class System(MemObject):
cache_line_size = Param.Unsigned(64, "Cache line size in bytes")
redirect_paths = VectorParam.RedirectPath([], "Path redirections")
exit_on_work_items = Param.Bool(False, "Exit from the simulation loop when "
"encountering work item annotations.")
work_item_id = Param.Int(-1, "specific work item id")

View File

@@ -50,6 +50,7 @@
#include <unistd.h>
#include <array>
#include <climits>
#include <csignal>
#include <map>
#include <string>
@@ -67,6 +68,7 @@
#include "sim/emul_driver.hh"
#include "sim/fd_array.hh"
#include "sim/fd_entry.hh"
#include "sim/redirect_path.hh"
#include "sim/syscall_desc.hh"
#include "sim/system.hh"
@@ -101,6 +103,14 @@
using namespace std;
using namespace TheISA;
static std::string
normalize(std::string& directory)
{
if (directory.back() != '/')
directory += '/';
return directory;
}
Process::Process(ProcessParams *params, EmulationPageTable *pTable,
ObjectFile *obj_file)
: SimObject(params), system(params->system),
@@ -111,8 +121,10 @@ Process::Process(ProcessParams *params, EmulationPageTable *pTable,
initVirtMem(system->getSystemPort(), this,
SETranslatingPortProxy::Always),
objFile(obj_file),
argv(params->cmd), envp(params->env), cwd(params->cwd),
argv(params->cmd), envp(params->env),
executable(params->executable),
tgtCwd(normalize(params->cwd)),
hostCwd(checkPathRedirect(tgtCwd)),
_uid(params->uid), _euid(params->euid),
_gid(params->gid), _egid(params->egid),
_pid(params->pid), _ppid(params->ppid),
@@ -441,6 +453,42 @@ Process::findDriver(std::string filename)
return nullptr;
}
std::string
Process::checkPathRedirect(const std::string &filename)
{
// If the input parameter contains a relative path, convert it. Note,
// the return value for this method should always return an absolute
// path on the host filesystem. The return value will be used to
// open and manipulate the path specified by the input parameter. Since
// all filesystem handling in syscall mode is passed through to the host,
// we deal only with host paths.
auto host_fs_abs_path = absolutePath(filename, true);
for (auto path : system->redirectPaths) {
// Search through the redirect paths to see if a starting substring of
// our path falls into any buckets which need to redirected.
if (startswith(host_fs_abs_path, path->appPath())) {
std::string tail = host_fs_abs_path.substr(path->appPath().size());
// If this path needs to be redirected, search through a list
// of targets to see if we can match a valid file (or directory).
for (auto host_path : path->hostPaths()) {
if (access((host_path + tail).c_str(), R_OK) == 0) {
// Return the valid match.
return host_path + tail;
}
}
// The path needs to be redirected, but the file or directory
// does not exist on the host filesystem. Return the first
// host path as a default.
return path->hostPaths()[0] + tail;
}
}
// The path does not need to be redirected.
return host_fs_abs_path;
}
void
Process::updateBias()
{
@@ -489,6 +537,33 @@ Process::getStartPC()
return interp ? interp->entryPoint() : objFile->entryPoint();
}
std::string
Process::absolutePath(const std::string &filename, bool host_filesystem)
{
if (filename.empty() || startswith(filename, "/"))
return filename;
// Verify that the current working directories are initialized properly.
// These members should be set initially via params from 'Process.py',
// although they may change over time depending on what the application
// does during simulation.
assert(!tgtCwd.empty());
assert(!hostCwd.empty());
// Construct the absolute path given the current working directory for
// either the host filesystem or target filesystem. The distinction only
// matters if filesystem redirection is utilized in the simulation.
auto path_base = host_filesystem ? hostCwd : tgtCwd;
// Add a trailing '/' if the current working directory did not have one.
normalize(path_base);
// Append the filename onto the current working path.
auto absolute_path = path_base + filename;
return absolute_path;
}
Process *
ProcessParams::create()
{
@@ -649,17 +724,3 @@ ProcessParams::create()
fatal("Unknown error creating process object.");
return process;
}
std::string
Process::fullPath(const std::string &file_name)
{
if (file_name[0] == '/' || cwd.empty())
return file_name;
std::string full = cwd;
if (cwd[cwd.size() - 1] != '/')
full += '/';
return full + file_name;
}

View File

@@ -91,8 +91,6 @@ class Process : public SimObject
inline void setpgid(uint64_t pgid) { _pgid = pgid; }
const char *progName() const { return executable.c_str(); }
std::string fullPath(const std::string &filename);
std::string getcwd() const { return cwd; }
/**
* Find an emulated device driver.
@@ -186,9 +184,46 @@ class Process : public SimObject
ObjectFile *objFile;
std::vector<std::string> argv;
std::vector<std::string> envp;
std::string cwd;
std::string executable;
/**
* Return an absolute path given a relative path paired with the current
* working directory of the process running under simulation.
*
* @param path The relative path (generally a filename) that needs the
* current working directory prepended.
* @param host_fs A flag which determines whether to return a
* path for the host filesystem or the filesystem of the process running
* under simulation. Only matters if filesysem redirection is used to
* replace files (or directories) that would normally appear via the
* host filesystem.
* @return String containing an absolute path.
*/
std::string absolutePath(const std::string &path, bool host_fs);
/**
* Redirect file path if it matches any keys initialized by system object.
* @param filename An input parameter containing either a relative path
* or an absolute path. If given a relative path, the path will be
* prepended to the current working directory of the simulation with
* respect to the host filesystem.
* @return String containing an absolute path.
*/
std::string checkPathRedirect(const std::string &filename);
/**
* The cwd members are used to track changes to the current working
* directory for the purpose of executing system calls which depend on
* relative paths (i.e. open, chdir).
*
* The tgt member and host member may differ if the path for the current
* working directory is redirected to point to a different location
* (i.e. `cd /proc` should point to '$(gem5_repo)/m5out/fs/proc'
* instead of '/proc').
*/
std::string tgtCwd;
std::string hostCwd;
// Id of the owner of the process
uint64_t _uid;
uint64_t _euid;

63
src/sim/redirect_path.cc Normal file
View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2015 Advanced Micro Devices, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: David Hashe
*/
#include "sim/redirect_path.hh"
#include <unistd.h>
static std::string
normalizePath(std::string path)
{
char buf[PATH_MAX];
std::string gem5_cwd = getcwd(buf, PATH_MAX);
if (!startswith(path, "/")) {
path = realpath((gem5_cwd + "/" + path).c_str(), buf);
}
if (path[path.length()-1] != '/') path.push_back('/');
return path;
}
RedirectPath::RedirectPath(const RedirectPathParams *p)
: SimObject(p)
{
_appPath = normalizePath(p->app_path);
for (auto hp : p->host_paths) {
_hostPaths.push_back(normalizePath(hp));
}
}
RedirectPath*
RedirectPathParams::create()
{
return new RedirectPath(this);
}

65
src/sim/redirect_path.hh Normal file
View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 2015 Advanced Micro Devices, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: David Hashe
*/
#ifndef __SIM_REDIRECT_PATH_HH__
#define __SIM_REDIRECT_PATH_HH__
#include <string>
#include <vector>
#include "params/RedirectPath.hh"
#include "sim/sim_object.hh"
/**
* RedirectPath stores a mapping from one 'appPath' to a vector of
* 'hostPath'. Each 'appPath' and 'hostPath' is a filesystem path.
* Used by process.cc to redirect syscall accesses to different directories.
*/
class RedirectPath : public SimObject
{
public:
RedirectPath(const RedirectPathParams *p);
const std::string& appPath() { return _appPath; };
const std::vector<std::string>& hostPaths() { return _hostPaths; };
protected:
/**
* An appPath is a path which needs to be redirected and replaced
* by one of the corresponding hostPath (when accessing files on the host
* filesystem.)
*/
// _appPath holds the path as it would appear from an app's perspective.
std::string _appPath;
// _hostPaths holds a set of host filesystem paths
std::vector<std::string> _hostPaths;
};
#endif

View File

@@ -388,7 +388,7 @@ getcwdFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
BufferArg buf(buf_ptr, size);
// Is current working directory defined?
string cwd = p->getcwd();
string cwd = p->tgtCwd;
if (!cwd.empty()) {
if (cwd.length() >= size) {
// Buffer too small
@@ -425,8 +425,8 @@ readlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc,
if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
return -EFAULT;
// Adjust path for current working directory
path = p->fullPath(path);
// Adjust path for cwd and redirection
path = p->checkPathRedirect(path);
Addr buf_ptr = p->getSyscallArg(tc, index);
size_t bufsiz = p->getSyscallArg(tc, index);
@@ -491,7 +491,7 @@ unlinkHelper(SyscallDesc *desc, int num, Process *p, ThreadContext *tc,
if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
return -EFAULT;
path = p->fullPath(path);
path = p->checkPathRedirect(path);
int result = unlink(path.c_str());
return (result == -1) ? -errno : result;
@@ -510,8 +510,8 @@ linkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
if (!virt_mem.tryReadString(new_path, p->getSyscallArg(tc, index)))
return -EFAULT;
path = p->fullPath(path);
new_path = p->fullPath(new_path);
path = p->absolutePath(path, true);
new_path = p->absolutePath(new_path, true);
int result = link(path.c_str(), new_path.c_str());
return (result == -1) ? -errno : result;
@@ -530,8 +530,8 @@ symlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
if (!virt_mem.tryReadString(new_path, p->getSyscallArg(tc, index)))
return -EFAULT;
path = p->fullPath(path);
new_path = p->fullPath(new_path);
path = p->absolutePath(path, true);
new_path = p->absolutePath(new_path, true);
int result = symlink(path.c_str(), new_path.c_str());
return (result == -1) ? -errno : result;
@@ -540,18 +540,15 @@ symlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
SyscallReturn
mkdirFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
{
string path;
int index = 0;
std::string path;
if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
return -EFAULT;
// Adjust path for current working directory
path = p->fullPath(path);
path = p->checkPathRedirect(path);
mode_t mode = p->getSyscallArg(tc, index);
int result = mkdir(path.c_str(), mode);
auto result = mkdir(path.c_str(), mode);
return (result == -1) ? -errno : result;
}
@@ -569,9 +566,9 @@ renameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
if (!tc->getMemProxy().tryReadString(new_name, p->getSyscallArg(tc, index)))
return -EFAULT;
// Adjust path for current working directory
old_name = p->fullPath(old_name);
new_name = p->fullPath(new_name);
// Adjust path for cwd and redirection
old_name = p->checkPathRedirect(old_name);
new_name = p->checkPathRedirect(new_name);
int64_t result = rename(old_name.c_str(), new_name.c_str());
return (result == -1) ? -errno : result;
@@ -588,8 +585,8 @@ truncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
off_t length = p->getSyscallArg(tc, index);
// Adjust path for current working directory
path = p->fullPath(path);
// Adjust path for cwd and redirection
path = p->checkPathRedirect(path);
int result = truncate(path.c_str(), length);
return (result == -1) ? -errno : result;
@@ -623,8 +620,8 @@ truncate64Func(SyscallDesc *desc, int num,
int64_t length = process->getSyscallArg(tc, index, 64);
// Adjust path for current working directory
path = process->fullPath(path);
// Adjust path for cwd and redirection
path = process->checkPathRedirect(path);
#if NO_STAT64
int result = truncate(path.c_str(), length);
@@ -680,8 +677,8 @@ chownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
uint32_t group = p->getSyscallArg(tc, index);
gid_t hostGroup = group;
// Adjust path for current working directory
path = p->fullPath(path);
// Adjust path for cwd and redirection
path = p->checkPathRedirect(path);
int result = chown(path.c_str(), hostOwner, hostGroup);
return (result == -1) ? -errno : result;
@@ -1068,8 +1065,8 @@ accessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc,
if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
return -EFAULT;
// Adjust path for current working directory
path = p->fullPath(path);
// Adjust path for cwd and redirection
path = p->checkPathRedirect(path);
mode_t mode = p->getSyscallArg(tc, index);
@@ -1091,7 +1088,7 @@ mknodFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
return -EFAULT;
path = p->fullPath(path);
path = p->checkPathRedirect(path);
mode_t mode = p->getSyscallArg(tc, index);
dev_t dev = p->getSyscallArg(tc, index);
@@ -1107,10 +1104,23 @@ chdirFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
return -EFAULT;
path = p->fullPath(path);
std::string tgt_cwd;
if (startswith(path, "/")) {
tgt_cwd = path;
} else {
char buf[PATH_MAX];
tgt_cwd = realpath((p->tgtCwd + "/" + path).c_str(), buf);
}
std::string host_cwd = p->checkPathRedirect(tgt_cwd);
auto result = chdir(path.c_str());
return (result == -1) ? -errno : result;
int result = chdir(host_cwd.c_str());
if (result == -1)
return -errno;
p->hostCwd = host_cwd;
p->tgtCwd = tgt_cwd;
return result;
}
SyscallReturn
@@ -1121,7 +1131,7 @@ rmdirFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
return -EFAULT;
path = p->fullPath(path);
path = p->checkPathRedirect(path);
auto result = rmdir(path.c_str());
return (result == -1) ? -errno : result;

View File

@@ -837,14 +837,18 @@ openImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc,
* In every case, we should have a full path (which is relevant to the
* host) to work with after this block has been passed.
*/
if (!isopenat || (isopenat && tgt_dirfd == OS::TGT_AT_FDCWD)) {
path = p->fullPath(path);
std::string redir_path = path;
std::string abs_path = path;
if (!isopenat || tgt_dirfd == OS::TGT_AT_FDCWD) {
abs_path = p->absolutePath(path, true);
redir_path = p->checkPathRedirect(path);
} else if (!startswith(path, "/")) {
std::shared_ptr<FDEntry> fdep = ((*p->fds)[tgt_dirfd]);
auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
if (!ffdp)
return -EBADF;
path.insert(0, ffdp->getFileName() + "/");
abs_path = ffdp->getFileName() + path;
redir_path = p->checkPathRedirect(abs_path);
}
/**
@@ -853,13 +857,13 @@ openImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc,
* the process class through Python; this allows us to create a file
* descriptor for subsequent ioctl or mmap calls.
*/
if (startswith(path, "/dev/")) {
std::string filename = path.substr(strlen("/dev/"));
if (startswith(abs_path, "/dev/")) {
std::string filename = abs_path.substr(strlen("/dev/"));
EmulatedDriver *drv = p->findDriver(filename);
if (drv) {
DPRINTF_SYSCALL(Verbose, "open%s: passing call to "
"driver open with path[%s]\n",
isopenat ? "at" : "", path.c_str());
isopenat ? "at" : "", abs_path.c_str());
return drv->open(p, tc, mode, host_flags);
}
/**
@@ -869,28 +873,49 @@ openImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc,
}
/**
* Some special paths and files cannot be called on the host and need
* to be handled as special cases inside the simulator.
* If the full path that was created above does not match any of the
* special cases, pass it through to the open call on the host to let
* the host open the file on our behalf.
* If the host cannot open the file, return the host's error code back
* through the system call to the simulated process.
* We make several attempts resolve a call to open.
*
* 1) Resolve any path redirection before hand. This will set the path
* up with variable 'redir_path' which may contain a modified path or
* the original path value. This should already be done in prior code.
* 2) Try to handle the access using 'special_paths'. Some special_paths
* and files cannot be called on the host and need to be handled as
* special cases inside the simulator. These special_paths are handled by
* C++ routines to provide output back to userspace.
* 3) If the full path that was created above does not match any of the
* special cases, pass it through to the open call on the __HOST__ to let
* the host open the file on our behalf. Again, the openImpl tries to
* USE_THE_HOST_FILESYSTEM_OPEN (with a possible redirection to the
* faux-filesystem files). The faux-filesystem is dynamically created
* during simulator configuration using Python functions.
* 4) If the host cannot open the file, the open attempt failed in "3)".
* Return the host's error code back through the system call to the
* simulated process. If running a debug trace, also notify the user that
* the open call failed.
*
* Any success will set sim_fd to something other than -1 and skip the
* next conditions effectively bypassing them.
*/
int sim_fd = -1;
std::string used_path;
std::vector<std::string> special_paths =
{ "/proc/", "/system/", "/sys/", "/platform/", "/etc/passwd" };
{ "/proc/meminfo/", "/system/", "/sys/", "/platform/",
"/etc/passwd" };
for (auto entry : special_paths) {
if (startswith(path, entry))
sim_fd = OS::openSpecialFile(path, p, tc);
if (startswith(path, entry)) {
sim_fd = OS::openSpecialFile(abs_path, p, tc);
used_path = abs_path;
}
}
if (sim_fd == -1) {
sim_fd = open(path.c_str(), host_flags, mode);
sim_fd = open(redir_path.c_str(), host_flags, mode);
used_path = redir_path;
}
if (sim_fd == -1) {
int local = -errno;
DPRINTF_SYSCALL(Verbose, "open%s: failed -> path:%s\n",
isopenat ? "at" : "", path.c_str());
DPRINTF_SYSCALL(Verbose, "open%s: failed -> path:%s "
"(inferred from:%s)\n", isopenat ? "at" : "",
used_path.c_str(), path.c_str());
return local;
}
@@ -904,8 +929,9 @@ openImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc,
*/
auto ffdp = std::make_shared<FileFDEntry>(sim_fd, host_flags, path, 0);
int tgt_fd = p->fds->allocFD(ffdp);
DPRINTF_SYSCALL(Verbose, "open%s: sim_fd[%d], target_fd[%d] -> path:%s\n",
isopenat ? "at" : "", sim_fd, tgt_fd, path.c_str());
DPRINTF_SYSCALL(Verbose, "open%s: sim_fd[%d], target_fd[%d] -> path:%s\n"
"(inferred from:%s)\n", isopenat ? "at" : "",
sim_fd, tgt_fd, used_path.c_str(), path.c_str());
return tgt_fd;
}
@@ -995,9 +1021,9 @@ renameatFunc(SyscallDesc *desc, int callnum, Process *process,
process->getSyscallArg(tc, index)))
return -EFAULT;
// Adjust path for current working directory
old_name = process->fullPath(old_name);
new_name = process->fullPath(new_name);
// Adjust path for cwd and redirection
old_name = process->checkPathRedirect(old_name);
new_name = process->checkPathRedirect(new_name);
int result = rename(old_name.c_str(), new_name.c_str());
return (result == -1) ? -errno : result;
@@ -1043,8 +1069,8 @@ chmodFunc(SyscallDesc *desc, int callnum, Process *process,
// XXX translate mode flags via OS::something???
hostMode = mode;
// Adjust path for current working directory
path = process->fullPath(path);
// Adjust path for cwd and redirection
path = process->checkPathRedirect(path);
// do the chmod
int result = chmod(path.c_str(), hostMode);
@@ -1244,8 +1270,8 @@ statFunc(SyscallDesc *desc, int callnum, Process *process,
}
Addr bufPtr = process->getSyscallArg(tc, index);
// Adjust path for current working directory
path = process->fullPath(path);
// Adjust path for cwd and redirection
path = process->checkPathRedirect(path);
struct stat hostBuf;
int result = stat(path.c_str(), &hostBuf);
@@ -1273,8 +1299,8 @@ stat64Func(SyscallDesc *desc, int callnum, Process *process,
return -EFAULT;
Addr bufPtr = process->getSyscallArg(tc, index);
// Adjust path for current working directory
path = process->fullPath(path);
// Adjust path for cwd and redirection
path = process->checkPathRedirect(path);
#if NO_STAT64
struct stat hostBuf;
@@ -1310,8 +1336,8 @@ fstatat64Func(SyscallDesc *desc, int callnum, Process *process,
return -EFAULT;
Addr bufPtr = process->getSyscallArg(tc, index);
// Adjust path for current working directory
path = process->fullPath(path);
// Adjust path for cwd and redirection
path = process->checkPathRedirect(path);
#if NO_STAT64
struct stat hostBuf;
@@ -1376,8 +1402,8 @@ lstatFunc(SyscallDesc *desc, int callnum, Process *process,
}
Addr bufPtr = process->getSyscallArg(tc, index);
// Adjust path for current working directory
path = process->fullPath(path);
// Adjust path for cwd and redirection
path = process->checkPathRedirect(path);
struct stat hostBuf;
int result = lstat(path.c_str(), &hostBuf);
@@ -1405,8 +1431,8 @@ lstat64Func(SyscallDesc *desc, int callnum, Process *process,
}
Addr bufPtr = process->getSyscallArg(tc, index);
// Adjust path for current working directory
path = process->fullPath(path);
// Adjust path for cwd and redirection
path = process->checkPathRedirect(path);
#if NO_STAT64
struct stat hostBuf;
@@ -1469,8 +1495,8 @@ statfsFunc(SyscallDesc *desc, int callnum, Process *process,
}
Addr bufPtr = process->getSyscallArg(tc, index);
// Adjust path for current working directory
path = process->fullPath(path);
// Adjust path for cwd and redirection
path = process->checkPathRedirect(path);
struct statfs hostBuf;
int result = statfs(path.c_str(), &hostBuf);
@@ -1531,7 +1557,7 @@ cloneFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
pp->executable.assign(*(new std::string(p->progName())));
pp->cmd.push_back(*(new std::string(p->progName())));
pp->system = p->system;
pp->cwd.assign(p->getcwd());
pp->cwd.assign(p->tgtCwd);
pp->input.assign("stdin");
pp->output.assign("stdout");
pp->errout.assign("stderr");
@@ -2096,8 +2122,8 @@ utimesFunc(SyscallDesc *desc, int callnum, Process *process,
hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec);
}
// Adjust path for current working directory
path = process->fullPath(path);
// Adjust path for cwd and redirection
path = process->checkPathRedirect(path);
int result = utimes(path.c_str(), hostTimeval);
@@ -2159,7 +2185,7 @@ execveFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc)
pp->input.assign("cin");
pp->output.assign("cout");
pp->errout.assign("cerr");
pp->cwd.assign(p->getcwd());
pp->cwd.assign(p->tgtCwd);
pp->system = p->system;
/**
* Prevent process object creation with identical PIDs (which will trip

View File

@@ -70,6 +70,7 @@
#include "sim/byteswap.hh"
#include "sim/debug.hh"
#include "sim/full_system.hh"
#include "sim/redirect_path.hh"
/**
* To avoid linking errors with LTO, only include the header if we
@@ -111,8 +112,10 @@ System::System(Params *p)
thermalModel(p->thermal_model),
_params(p),
totalNumInsts(0),
instEventQueue("system instruction-based event queue")
instEventQueue("system instruction-based event queue"),
redirectPaths(p->redirect_paths)
{
// add self to global system list
systemList.push_back(this);

View File

@@ -64,6 +64,7 @@
#include "mem/port_proxy.hh"
#include "params/System.hh"
#include "sim/futex_map.hh"
#include "sim/redirect_path.hh"
#include "sim/se_signal.hh"
/**
@@ -628,6 +629,11 @@ class System : public MemObject
// receiver will delete the signal upon reception.
std::list<BasicSignal> signalList;
// Used by syscall-emulation mode. This member contains paths which need
// to be redirected to the faux-filesystem (a duplicate filesystem
// intended to replace certain files on the host filesystem).
std::vector<RedirectPath*> redirectPaths;
protected:
/**
@@ -647,7 +653,6 @@ class System : public MemObject
* @param section relevant section in the checkpoint
*/
virtual void unserializeSymtab(CheckpointIn &cp) {}
};
void printSystems();