Add weak linkage attributes for stubbing

Add weak linkage attribute to underlying kernel module and filedescriptors
to be able to replace with stub methods together with an example stub
implementation.

Change-Id: I766c51fceede7df16c599bd9f1874e31c264776d
diff --git a/driver_library/src/ethosu.cpp b/driver_library/src/ethosu.cpp
index 997e12a..0262429 100644
--- a/driver_library/src/ethosu.cpp
+++ b/driver_library/src/ethosu.cpp
@@ -33,8 +33,8 @@
 
 using namespace std;
 
-namespace {
-int eioctl(int fd, unsigned long cmd, void *data = nullptr) {
+namespace EthosU {
+__attribute__((weak)) int eioctl(int fd, unsigned long cmd, void *data = nullptr) {
     int ret = ::ioctl(fd, cmd, data);
     if (ret < 0) {
         throw EthosU::Exception("IOCTL failed");
@@ -43,10 +43,37 @@
     return ret;
 }
 
+__attribute__((weak)) int eopen(const char *pathname, int flags) {
+    int fd = ::open(pathname, flags);
+
+    if (fd < 0) {
+        throw Exception("Failed to open device");
+    }
+
+    return fd;
+}
+
+__attribute__((weak)) int epoll(struct pollfd *fds, nfds_t nfds, int timeout) {
+    return ::poll(fds, nfds, timeout);
+}
+
+__attribute__((weak)) int eclose(int fd) {
+    return ::close(fd);
+}
+__attribute((weak)) void *emmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) {
+    return ::mmap(addr, length, prot, flags, fd, offset);
+}
+
+__attribute__((weak)) int emunmap(void *addr, size_t length) {
+    return ::munmap(addr, length);
+}
+
+} // namespace EthosU
+
 /****************************************************************************
  * TFL micro helpers
  ****************************************************************************/
-
+namespace {
 size_t getShapeSize(const flatbuffers::Vector<int32_t> *shape) {
     size_t size = 1;
 
@@ -151,16 +178,12 @@
 /****************************************************************************
  * Device
  ****************************************************************************/
-
 Device::Device(const char *device) {
-    fd = open(device, O_RDWR | O_NONBLOCK);
-    if (fd < 0) {
-        throw Exception("Failed to open device");
-    }
+    fd = eopen(device, O_RDWR | O_NONBLOCK);
 }
 
 Device::~Device() {
-    close(fd);
+    eclose(fd);
 }
 
 int Device::ioctl(unsigned long cmd, void *data) {
@@ -189,7 +212,7 @@
     ethosu_uapi_buffer_create uapi = {static_cast<uint32_t>(dataCapacity)};
     fd                             = device.ioctl(ETHOSU_IOCTL_BUFFER_CREATE, static_cast<void *>(&uapi));
 
-    void *d = ::mmap(nullptr, dataCapacity, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+    void *d = emmap(nullptr, dataCapacity, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
     if (d == MAP_FAILED) {
         throw Exception("MMap failed");
     }
@@ -198,7 +221,8 @@
 }
 
 Buffer::~Buffer() {
-    close(fd);
+    emunmap(dataPtr, dataCapacity);
+    eclose(fd);
 }
 
 size_t Buffer::capacity() const {
@@ -263,7 +287,7 @@
 }
 
 Network::~Network() {
-    close(fd);
+    eclose(fd);
 }
 
 int Network::ioctl(unsigned long cmd, void *data) {
@@ -307,7 +331,7 @@
  ****************************************************************************/
 
 Inference::~Inference() {
-    close(fd);
+    eclose(fd);
 }
 
 void Inference::create(std::vector<uint32_t> &counterConfigs, bool cycleCounterEnable = false) {
@@ -359,7 +383,7 @@
     pfd.events  = POLLIN | POLLERR;
     pfd.revents = 0;
 
-    int ret = ::poll(&pfd, 1, timeoutSec * 1000);
+    int ret = epoll(&pfd, 1, timeoutSec * 1000);
 
     cout << "Poll. ret=" << ret << ", revents=" << pfd.revents << endl;
 
diff --git a/driver_library/src/ethosu_stub.cpp b/driver_library/src/ethosu_stub.cpp
new file mode 100644
index 0000000..9dfc029
--- /dev/null
+++ b/driver_library/src/ethosu_stub.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2020-2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <uapi/ethosu.h>
+
+#include <ethosu.hpp>
+#include <exception>
+#include <iostream>
+
+#include <fcntl.h>
+#include <poll.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+namespace EthosU {
+int eopen(const char *p, int) {
+    std::cout << "Opened filedescriptor for " << p;
+    return 1;
+}
+
+int eclose(int) {
+    return 0;
+}
+
+void *emmap(void *, size_t length, int, int, int, off_t) {
+    void *d = malloc(length);
+    return d;
+}
+
+int emunmap(void *addr, size_t) {
+    free(addr);
+    return 0;
+}
+
+int eioctl(int, unsigned long cmd, void *) {
+    int result = 0;
+    using namespace EthosU;
+
+    switch (cmd) {
+    case ETHOSU_IOCTL_PING:
+        return result;
+    case ETHOSU_IOCTL_VERSION_REQ:
+        return result;
+    case ETHOSU_IOCTL_CAPABILITIES_REQ:
+        return result;
+    case ETHOSU_IOCTL_BUFFER_CREATE:
+        return result;
+    case ETHOSU_IOCTL_BUFFER_SET:
+        return result;
+    case ETHOSU_IOCTL_BUFFER_GET:
+        return result;
+    case ETHOSU_IOCTL_NETWORK_CREATE:
+        return result;
+    case ETHOSU_IOCTL_INFERENCE_CREATE:
+        return result;
+    case ETHOSU_IOCTL_INFERENCE_STATUS:
+        return result;
+    default:
+        throw EthosU::Exception("Unknown IOCTL");
+    }
+}
+
+int epoll(struct pollfd *, nfds_t, int timeout) {
+    sleep(timeout / 2);
+    return 1;
+}
+} // namespace EthosU