syscall emulation: clean up & comment SyscallReturn

This commit is contained in:
Steve Reinhardt
2014-05-12 14:23:31 -07:00
parent 72403cb595
commit 109908c2a6
8 changed files with 82 additions and 55 deletions

View File

@@ -220,19 +220,18 @@ AlphaLiveProcess::setSyscallArg(ThreadContext *tc,
}
void
AlphaLiveProcess::setSyscallReturn(ThreadContext *tc,
SyscallReturn return_value)
AlphaLiveProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
{
// check for error condition. Alpha syscall convention is to
// indicate success/failure in reg a3 (r19) and put the
// return value itself in the standard return value reg (v0).
if (return_value.successful()) {
if (sysret.successful()) {
// no error
tc->setIntReg(SyscallSuccessReg, 0);
tc->setIntReg(ReturnValueReg, return_value.value());
tc->setIntReg(ReturnValueReg, sysret.returnValue());
} else {
// got an error, return details
tc->setIntReg(SyscallSuccessReg, (IntReg)-1);
tc->setIntReg(ReturnValueReg, -return_value.value());
tc->setIntReg(ReturnValueReg, sysret.errnoValue());
}
}

View File

@@ -454,15 +454,13 @@ ArmLiveProcess64::setSyscallArg(ThreadContext *tc,
}
void
ArmLiveProcess32::setSyscallReturn(ThreadContext *tc,
SyscallReturn return_value)
ArmLiveProcess32::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
{
tc->setIntReg(ReturnValueReg, return_value.value());
tc->setIntReg(ReturnValueReg, sysret.encodedValue());
}
void
ArmLiveProcess64::setSyscallReturn(ThreadContext *tc,
SyscallReturn return_value)
ArmLiveProcess64::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
{
tc->setIntReg(ReturnValueReg, return_value.value());
tc->setIntReg(ReturnValueReg, sysret.encodedValue());
}

View File

@@ -197,16 +197,15 @@ MipsLiveProcess::setSyscallArg(ThreadContext *tc,
}
void
MipsLiveProcess::setSyscallReturn(ThreadContext *tc,
SyscallReturn return_value)
MipsLiveProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
{
if (return_value.successful()) {
if (sysret.successful()) {
// no error
tc->setIntReg(SyscallSuccessReg, 0);
tc->setIntReg(ReturnValueReg, return_value.value());
tc->setIntReg(ReturnValueReg, sysret.returnValue());
} else {
// got an error, return details
tc->setIntReg(SyscallSuccessReg, (IntReg) -1);
tc->setIntReg(ReturnValueReg, -return_value.value());
tc->setIntReg(ReturnValueReg, sysret.errnoValue());
}
}

View File

@@ -277,15 +277,14 @@ PowerLiveProcess::setSyscallArg(ThreadContext *tc,
}
void
PowerLiveProcess::setSyscallReturn(ThreadContext *tc,
SyscallReturn return_value)
PowerLiveProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
{
Cr cr = tc->readIntReg(INTREG_CR);
if (return_value.successful()) {
if (sysret.successful()) {
cr.cr0.so = 0;
} else {
cr.cr0.so = 1;
}
tc->setIntReg(INTREG_CR, cr);
tc->setIntReg(ReturnValueReg, return_value.value());
tc->setIntReg(ReturnValueReg, sysret.encodedValue());
}

View File

@@ -532,26 +532,25 @@ Sparc64LiveProcess::setSyscallArg(ThreadContext *tc, int i, IntReg val)
}
void
SparcLiveProcess::setSyscallReturn(ThreadContext *tc,
SyscallReturn return_value)
SparcLiveProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret)
{
// check for error condition. SPARC syscall convention is to
// indicate success/failure in reg the carry bit of the ccr
// and put the return value itself in the standard return value reg ().
PSTATE pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE);
if (return_value.successful()) {
if (sysret.successful()) {
// no error, clear XCC.C
tc->setIntReg(NumIntArchRegs + 2,
tc->readIntReg(NumIntArchRegs + 2) & 0xEE);
IntReg val = return_value.value();
tc->readIntReg(NumIntArchRegs + 2) & 0xEE);
IntReg val = sysret.returnValue();
if (pstate.am)
val = bits(val, 31, 0);
tc->setIntReg(ReturnValueReg, val);
} else {
// got an error, set XCC.C
tc->setIntReg(NumIntArchRegs + 2,
tc->readIntReg(NumIntArchRegs + 2) | 0x11);
IntReg val = -return_value.value();
tc->readIntReg(NumIntArchRegs + 2) | 0x11);
IntReg val = sysret.errnoValue();
if (pstate.am)
val = bits(val, 31, 0);
tc->setIntReg(ReturnValueReg, val);

View File

@@ -678,9 +678,9 @@ I386LiveProcess::argsInit(int intSize, int pageSize)
}
void
X86LiveProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn return_value)
X86LiveProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn retval)
{
tc->setIntReg(INTREG_RAX, return_value.value());
tc->setIntReg(INTREG_RAX, retval.encodedValue());
}
X86ISA::IntReg

View File

@@ -69,7 +69,7 @@ SyscallDesc::doSyscall(int callnum, LiveProcess *process, ThreadContext *tc)
SyscallReturn retval = (*funcPtr)(this, callnum, process, tc);
DPRINTFR(SyscallVerbose, "%d: %s: syscall %s returns %d\n",
curTick(),tc->getCpuPtr()->name(), name, retval.value());
curTick(), tc->getCpuPtr()->name(), name, retval.encodedValue());
if (!(flags & SyscallDesc::SuppressReturnValue))
process->setSyscallReturn(tc, retval);
@@ -366,7 +366,7 @@ readlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc,
string path;
if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
return (TheISA::IntReg)-EFAULT;
return -EFAULT;
// Adjust path for current working directory
path = p->fullPath(path);
@@ -390,7 +390,7 @@ unlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
int index = 0;
if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
return (TheISA::IntReg)-EFAULT;
return -EFAULT;
// Adjust path for current working directory
path = p->fullPath(path);
@@ -407,7 +407,7 @@ mkdirFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
int index = 0;
if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
return (TheISA::IntReg)-EFAULT;
return -EFAULT;
// Adjust path for current working directory
path = p->fullPath(path);
@@ -864,7 +864,7 @@ accessFunc(SyscallDesc *desc, int callnum, LiveProcess *p, ThreadContext *tc,
{
string path;
if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index)))
return (TheISA::IntReg)-EFAULT;
return -EFAULT;
// Adjust path for current working directory
path = p->fullPath(path);

View File

@@ -33,38 +33,71 @@
#include "base/types.hh"
/**
* This class represents the return value from an emulated system call,
* including any errno setting.
*
* On some platforms, the return value and errno are encoded in a
* single signed integer. A value less than zero but greater than
* -4096 indicates an error, and the value is the negation of the
* errno value. Otherwise, the call was successful and the integer is
* the return value. (Large negative numbers are considered
* successful to allow syscalls to return pointers to high memory,
* e.g., stack addresses.) See, for example, Appendix A of the AMD64
* ABI spec at http://www.x86-64.org/documentation/abi.pdf.
*
* Other platforms use a more complex interface, returning a value and
* an error code in separate registers.
*
* This class is designed to support both types of interfaces.
*/
class SyscallReturn
{
public:
template <class T>
SyscallReturn(T v, bool s)
{
retval = (uint64_t)v;
success = s;
}
template <class T>
SyscallReturn(T v)
{
success = (v >= 0);
retval = (uint64_t)v;
}
/// For simplicity, allow the object to be initialized with a
/// single signed integer using the same positive=success,
/// negative=-errno convention described above.
///
/// Typically this constructor is used as a default type
/// conversion, so a bare integer is used where a SyscallReturn
/// value is expected, e.g., as the return value from a system
/// call emulation function ('return 0;' or 'return -EFAULT;').
SyscallReturn(int64_t v)
: value(v)
{}
~SyscallReturn() {}
SyscallReturn& operator=(const SyscallReturn& s)
/// Was the system call successful?
bool successful() const
{
retval = s.retval;
success = s.success;
return *this;
return (value >= 0 || value <= -4096);
}
bool successful() { return success; }
uint64_t value() { return retval; }
/// The return value
int64_t returnValue() const
{
assert(successful());
return value;
}
private:
uint64_t retval;
bool success;
/// The errno value
int errnoValue() const
{
assert(!successful());
return -value;
}
/// The encoded value (as described above)
int64_t encodedValue() const
{
return value;
}
private:
int64_t value;
};
#endif