sim-se: add ability to get/set sock metadata

Add getsockopt, getsockname, setsockname, and getpeername
system calls.

Change-Id: Ifa1d9a95f15b4fb12859dbfd3c4bd248de2e3d32
Reviewed-on: https://gem5-review.googlesource.com/c/12116
Reviewed-by: Anthony Gutierrez <anthony.gutierrez@amd.com>
Maintainer: Anthony Gutierrez <anthony.gutierrez@amd.com>
diff --git a/src/arch/x86/linux/process.cc b/src/arch/x86/linux/process.cc
index 03a88fc..2fe99e0 100644
--- a/src/arch/x86/linux/process.cc
+++ b/src/arch/x86/linux/process.cc
@@ -273,11 +273,11 @@
     /*  48 */ SyscallDesc("shutdown", shutdownFunc),
     /*  49 */ SyscallDesc("bind", bindFunc),
     /*  50 */ SyscallDesc("listen", listenFunc),
-    /*  51 */ SyscallDesc("getsockname", unimplementedFunc),
-    /*  52 */ SyscallDesc("getpeername", unimplementedFunc),
+    /*  51 */ SyscallDesc("getsockname", getsocknameFunc),
+    /*  52 */ SyscallDesc("getpeername", getpeernameFunc),
     /*  53 */ SyscallDesc("socketpair", socketpairFunc<X86Linux64>),
-    /*  54 */ SyscallDesc("setsockopt", unimplementedFunc),
-    /*  55 */ SyscallDesc("getsockopt", unimplementedFunc),
+    /*  54 */ SyscallDesc("setsockopt", setsockoptFunc),
+    /*  55 */ SyscallDesc("getsockopt", getsockoptFunc),
     /*  56 */ SyscallDesc("clone", cloneFunc<X86Linux64>),
     /*  57 */ SyscallDesc("fork", unimplementedFunc),
     /*  58 */ SyscallDesc("vfork", unimplementedFunc),
diff --git a/src/sim/syscall_emul.cc b/src/sim/syscall_emul.cc
index 74ca1e9..25e0b68 100644
--- a/src/sim/syscall_emul.cc
+++ b/src/sim/syscall_emul.cc
@@ -1567,3 +1567,137 @@
     return (sent_size < 0) ? -local_errno : sent_size;
 }
 
+SyscallReturn
+getsockoptFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+    // union of all possible return value types from getsockopt
+    union val {
+        int i_val;
+        long l_val;
+        struct linger linger_val;
+        struct timeval timeval_val;
+    } val;
+
+    int index = 0;
+    int tgt_fd = p->getSyscallArg(tc, index);
+    int level = p->getSyscallArg(tc, index);
+    int optname = p->getSyscallArg(tc, index);
+    Addr valPtr = p->getSyscallArg(tc, index);
+    Addr lenPtr = p->getSyscallArg(tc, index);
+
+    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
+    if (!sfdp)
+        return -EBADF;
+    int sim_fd = sfdp->getSimFD();
+
+    socklen_t len = sizeof(val);
+    int status = getsockopt(sim_fd, level, optname, &val, &len);
+
+    if (status == -1)
+        return -errno;
+
+    // copy val to valPtr and pass it on
+    BufferArg valBuf(valPtr, sizeof(val));
+    memcpy(valBuf.bufferPtr(), &val, sizeof(val));
+    valBuf.copyOut(tc->getMemProxy());
+
+    // copy len to lenPtr and pass  it on
+    BufferArg lenBuf(lenPtr, sizeof(len));
+    memcpy(lenBuf.bufferPtr(), &len, sizeof(len));
+    lenBuf.copyOut(tc->getMemProxy());
+
+    return status;
+}
+
+SyscallReturn
+getsocknameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+    int index = 0;
+    int tgt_fd = p->getSyscallArg(tc, index);
+    Addr addrPtr = p->getSyscallArg(tc, index);
+    Addr lenPtr = p->getSyscallArg(tc, index);
+
+    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
+    if (!sfdp)
+        return -EBADF;
+    int sim_fd = sfdp->getSimFD();
+
+    // lenPtr is an in-out paramenter:
+    // sending the address length in, conveying the final length out
+
+    // Read in the value of len from the passed pointer.
+    BufferArg lenBuf(lenPtr, sizeof(socklen_t));
+    lenBuf.copyIn(tc->getMemProxy());
+    socklen_t len = *(socklen_t *)lenBuf.bufferPtr();
+
+    struct sockaddr sa;
+    int status = getsockname(sim_fd, &sa, &len);
+
+    if (status == -1)
+        return -errno;
+
+    // Copy address to addrPtr and pass it on.
+    BufferArg addrBuf(addrPtr, sizeof(sa));
+    memcpy(addrBuf.bufferPtr(), &sa, sizeof(sa));
+    addrBuf.copyOut(tc->getMemProxy());
+
+    // Copy len to lenPtr and pass  it on.
+    *(socklen_t *)lenBuf.bufferPtr() = len;
+    lenBuf.copyOut(tc->getMemProxy());
+
+    return status;
+}
+
+SyscallReturn
+getpeernameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+    int index = 0;
+    int tgt_fd = p->getSyscallArg(tc, index);
+    Addr sockAddrPtr = p->getSyscallArg(tc, index);
+    Addr addrlenPtr = p->getSyscallArg(tc, index);
+
+    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
+    if (!sfdp)
+        return -EBADF;
+    int sim_fd = sfdp->getSimFD();
+
+    BufferArg bufAddrlen(addrlenPtr, sizeof(unsigned));
+    bufAddrlen.copyIn(tc->getMemProxy());
+    BufferArg bufSock(sockAddrPtr, *(unsigned *)bufAddrlen.bufferPtr());
+
+    int retval = getpeername(sim_fd,
+                             (struct sockaddr *)bufSock.bufferPtr(),
+                             (unsigned *)bufAddrlen.bufferPtr());
+
+    if (retval != -1) {
+        bufSock.copyOut(tc->getMemProxy());
+        bufAddrlen.copyOut(tc->getMemProxy());
+    }
+
+    return (retval == -1) ? -errno : retval;
+}
+
+SyscallReturn
+setsockoptFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
+{
+    int index = 0;
+    int tgt_fd = p->getSyscallArg(tc, index);
+    int level = p->getSyscallArg(tc, index);
+    int optname = p->getSyscallArg(tc, index);
+    Addr valPtr = p->getSyscallArg(tc, index);
+    socklen_t len = p->getSyscallArg(tc, index);
+
+    BufferArg valBuf(valPtr, len);
+    valBuf.copyIn(tc->getMemProxy());
+
+    auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]);
+    if (!sfdp)
+        return -EBADF;
+    int sim_fd = sfdp->getSimFD();
+
+    int status = setsockopt(sim_fd, level, optname,
+                            (struct sockaddr *)valBuf.bufferPtr(), len);
+
+    return (status == -1) ? -errno : status;
+}
+
diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh
index 67fa9e3..c52589f 100644
--- a/src/sim/syscall_emul.hh
+++ b/src/sim/syscall_emul.hh
@@ -302,6 +302,10 @@
 SyscallReturn getpidFunc(SyscallDesc *desc, int num,
                          Process *p, ThreadContext *tc);
 
+// Target getpeername() handler.
+SyscallReturn getpeernameFunc(SyscallDesc *desc, int num,
+                              Process *p, ThreadContext *tc);
+
 // Target bind() handler.
 SyscallReturn bindFunc(SyscallDesc *desc, int num,
                        Process *p, ThreadContext *tc);
@@ -369,6 +373,18 @@
                          Process *p, ThreadContext *tc,
                          int index);
 
+// Target getsockopt() handler.
+SyscallReturn getsockoptFunc(SyscallDesc *desc, int num,
+                             Process *p, ThreadContext *tc);
+
+// Target setsockopt() handler.
+SyscallReturn setsockoptFunc(SyscallDesc *desc, int num,
+                             Process *p, ThreadContext *tc);
+
+// Target getsockname() handler.
+SyscallReturn getsocknameFunc(SyscallDesc *desc, int num,
+                              Process *p, ThreadContext *tc);
+
 /// Futex system call
 /// Implemented by Daniel Sanchez
 /// Used by printf's in multi-threaded apps