Skip to content

Commit

Permalink
Initial release for socket-based remote hosts on Linux
Browse files Browse the repository at this point in the history
  • Loading branch information
weliveindetail committed Jan 31, 2023
0 parents commit 9334235
Show file tree
Hide file tree
Showing 21 changed files with 1,865 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.cache
.vscode
build*
21 changes: 21 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
cmake_minimum_required(VERSION 3.13)
project(ez-clang-linux)

add_executable(ez-clang-linux-socket
main.cpp
src/abi.cpp
src/assert.cpp
src/protocol.cpp
src/raspi32.cpp
src/response.cpp
src/serialize.cpp
src/symbols.cpp
)

target_include_directories(ez-clang-linux-socket PRIVATE include)
target_link_libraries(ez-clang-linux-socket PRIVATE dl)
target_link_options(ez-clang-linux-socket PRIVATE -rdynamic)

set(EZ_RESTART_PORT 10819)
set(EZ_RESTART_BINARY ez-clang-linux-socket)
configure_file(ez-clang-linux.service.in ez-clang-linux-socket.service @ONLY)
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

75 changes: 75 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
## Build

```
> sudo apt update
> sudo apt install -y cmake ninja-build build-essential
> mkdir build
> cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=On .
-- The C compiler identification is GNU 10.2.1
-- The CXX compiler identification is GNU 10.2.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/ez/Develop/ez-clang-linux/build
> ninja -C build
> ./build/ez-clang-linux-socket 10819
Listening on port 10819
```

## Setup Systemd service for auto restart

```
> sudo cp build/ez-clang-linux-socket.service /etc/systemd/user/.
> sudo systemctl daemon-reload
> systemctl --user start ez-clang-linux-socket
> systemctl --user status ez-clang-linux-socket
● ez-clang-linux-socket.service - Permanent ez-clang-linux remote host service
Loaded: loaded (/etc/systemd/system/ez-clang-linux-socket.service; disabled; vendor preset: enabled)
Active: activating (start) since Thu 2023-01-26 15:22:14 CET; 3s ago
Cntrl PID: 18118 (ez-clang-linux-)
Tasks: 1 (limit: 1596)
CPU: 24ms
CGroup: /system.slice/ez-clang-linux-socket.service
└─18118 /home/ez/Develop/ez-clang-linux/build/ez-clang-linux-socket 10819
Jan 26 15:22:14 raspberrypi systemd[1]: Starting Permanent ez-clang-linux remote host service...
> systemctl enable --user ez-clang-linux-socket
Created symlink /home/ez/.config/systemd/user/multi-user.target.wants/ez-clang-linux-socket.service → /etc/xdg/systemd/user/ez-clang-linux-socket.service.
```

## Dump Systemd service log

```
> journalctl --user -u ez-clang-linux-socket.service --follow
Jan 30 10:39:42 raspberrypi systemd[1]: Starting Permanent ez-clang-linux remote host service...
Jan 30 10:40:36 raspberrypi ez-clang-linux-socket[4827]: Listening on port 10819
Jan 30 10:40:36 raspberrypi ez-clang-linux-socket[4827]: Connected
Jan 30 10:40:36 raspberrypi ez-clang-linux-socket[4827]: Send ->
Jan 30 10:40:36 raspberrypi ez-clang-linux-socket[4827]: 6a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Jan 30 10:40:36 raspberrypi ez-clang-linux-socket[4827]: Send ->
Jan 30 10:40:36 raspberrypi ez-clang-linux-socket[4827]: 05 00 00 00 00 00 00 00 30 2e 30 2e 35 00 80 39 01 00 00 00 00 00 80 00 00 00 00 00 00 01 00 00 00 00 00 00 00 15 00 00 00 00 00 00 00 5f 5f 65 7a 5f 63 6c 61 6e 67 5f 72 70 63 5f 6c 6f 6f 6b 75 70 94 26 01 00 00 00 00 00
Jan 30 10:40:36 raspberrypi ez-clang-linux-socket[4827]: Receive <-
Jan 30 10:40:36 raspberrypi ez-clang-linux-socket[4827]: 20 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Jan 30 10:40:36 raspberrypi ez-clang-linux-socket[4827]: Send ->
Jan 30 10:40:36 raspberrypi ez-clang-linux-socket[4827]: 21 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Jan 30 10:40:36 raspberrypi ez-clang-linux-socket[4827]: Send ->
Jan 30 10:40:36 raspberrypi ez-clang-linux-socket[4827]: 00
Jan 30 10:40:36 raspberrypi ez-clang-linux-socket[4827]: Receive <-
Jan 30 10:40:36 raspberrypi ez-clang-linux-socket[4827]: 20 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Jan 30 10:40:36 raspberrypi ez-clang-linux-socket[4827]: Exiting
Jan 30 10:40:36 raspberrypi systemd[1]: ez-clang-linux-socket.service: Succeeded.
Jan 30 10:40:36 raspberrypi systemd[1]: Started Permanent ez-clang-linux remote host service.
Jan 30 10:40:36 raspberrypi systemd[1]: ez-clang-linux-socket.service: Scheduled restart job, restart counter is at 2.
Jan 30 10:40:36 raspberrypi systemd[1]: Stopped Permanent ez-clang-linux remote host service.
Jan 30 10:40:36 raspberrypi systemd[1]: Starting Permanent ez-clang-linux remote host service...
Jan 30 10:40:37 raspberrypi ez-clang-linux-socket[4926]: Listening on port 10819
```
13 changes: 13 additions & 0 deletions ez-clang-linux.service.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[Unit]
Description=Permanent ez-clang-linux remote host service
After=network-online.target
StartLimitBurst=10
StartLimitIntervalSec=1

[Service]
Type=simple
ExecStart=@CMAKE_BINARY_DIR@/@EZ_RESTART_BINARY@ @EZ_RESTART_PORT@
Restart=always

[Install]
WantedBy=multi-user.target
34 changes: 34 additions & 0 deletions include/ez/abi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#ifndef EZ_ABI_H
#define EZ_ABI_H

#ifdef __cplusplus
#include <cstddef>
#include <cstdint>
#else
#include <stddef.h>
#include <stdint.h>
#endif

#ifdef __cplusplus
extern "C" {
#endif

#define EZ_CLANG_RPC_ENDPOINT(Name) char *Name(const char *Data, size_t Size)

// RPC endpoints:
EZ_CLANG_RPC_ENDPOINT(__ez_clang_rpc_lookup);
EZ_CLANG_RPC_ENDPOINT(__ez_clang_rpc_commit);
EZ_CLANG_RPC_ENDPOINT(__ez_clang_rpc_execute);
EZ_CLANG_RPC_ENDPOINT(__ez_clang_rpc_mem_read_cstring);

#undef EZ_CLANG_RPC_ENDPOINT

char *__ez_clang_inline_heap_acquire(size_t Bytes);
void __ez_clang_report_string(const char *Data, size_t Size);
void __ez_clang_report_value(uint32_t SeqID, const char *Blob, size_t Size);

#ifdef __cplusplus
} // extern "C"
#endif

#endif // EZ_ABI_H
27 changes: 27 additions & 0 deletions include/ez/assert.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#ifndef EZ_ASSERT_H
#define EZ_ASSERT_H

#include "support.h"

#include <cstdint>
#include <csetjmp>

#if defined(assert)
static_assert(false, "Internal assert() clashes with existing definition");
#endif

#if !defined(NDEBUG) // && defined(DEBUG)

void assert(bool Premise, const char *Description);
EZ_NORETURN void fail(const char *Description);

#else
# define assert(Premise, Description)
# define fail(Description)
#endif

extern jmp_buf GlobalAssertionFailureReturnPoint;
extern char *GlobalAssertionFailureBuffer;
extern uint32_t GlobalAssertionFailureBufferSize;

#endif // EZ_ASSERT_H
23 changes: 23 additions & 0 deletions include/ez/device.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#ifndef EZ_DEVICE_H
#define EZ_DEVICE_H

#include <cstddef>
#include <cstdint>
#include <string>

void device_notifyBoot();
void device_notifyReady();
void device_notifyTick();
void device_notifyShutdown();

void device_setupSendReceive();
void device_sendBytes(const char *Buffer, size_t Size);
bool device_receiveBytes(char Buffer[], uint32_t Count);

void device_flushReceiveBuffer();

// Ad-hoc device interface extensions for Linux/sockets support
char *device_allocCodeBuffer(size_t Size);
void device_listenOnPort(std::string PortStr);

#endif // EZ_DEVICE_H
47 changes: 47 additions & 0 deletions include/ez/protocol.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#ifndef EZ_PROTOCOL_H
#define EZ_PROTOCOL_H

#include "ez/abi.h"
#include "ez/serialize.h"
#include "ez/symbols.h"

#include <cstddef>
#include <cstdint>

typedef char* RPCEndpoint(const char *Data, size_t Size);

enum EPCOpCode : uint32_t {
Setup,
Hangup,
Result,
Call,
ReportValue,
ReportString,
LastOpC = ReportString
};

struct SetupInfo {
const char *Version;
char *CodeBuffer;
uint32_t CodeBufferSize;
uint32_t NumSymbols;
const Symbol *Symbols;
};

struct HeaderInfo {
uint32_t SeqID;
uint32_t OpCode;
uint32_t PayloadBytes;
RPCEndpoint *Handler;
};

bool receiveMessage(char Buffer[], uint32_t BufferSize, HeaderInfo &Msg);

void sendMessage(EPCOpCode OpC, uint32_t SeqID, const char Payload[],
uint32_t NumArgBytes);

void sendSetupMessage(char Buffer[], SetupInfo Info);

void sendHangupMessage(uint8_t ErrCode);

#endif // EZ_PROTOCOL_H
28 changes: 28 additions & 0 deletions include/ez/response.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#ifndef EZ_RESPONSE_H
#define EZ_RESPONSE_H

#include <cstddef>
#include <cstdint>

extern char *GlobalResponseBuffer;
extern size_t GlobalResponseCapacity;
extern const char *GlobalResponseBufferEnd;

char *responseAcquire(uint32_t ExpectedBytes);
char *responseFinalize(char *ResponseEnd);
const char *responseSetBuffer(char *InputEnd, size_t Capacity);
void responseClearBuffer();

const char *responseGetBuffer();
const char *responseGetLimit();

char *error(const char *Fmt, ...);
char *errorEx(char *Buffer, uint32_t Size, const char *Fmt, ...);

const char *errorGetBuffer(uint32_t &Size);
char *errorFinalize(uint32_t Length);

uint32_t formatlnBytesHex(char Buffer[], const char *Bytes,
size_t BytesRemaining, size_t LineMax = 0);

#endif // EZ_RESPONSE_H
21 changes: 21 additions & 0 deletions include/ez/serialize.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef EZ_SERIALIZE_H
#define EZ_SERIALIZE_H

#include <cstddef>
#include <cstdint>

uint32_t writeUInt64(char *Buffer, uint32_t Value);
uint32_t writeSInt64(char Buffer[], int32_t Value);
uint32_t writeBytes(char Buffer[], const void *Bytes, size_t Count);
uint32_t writeString(char Buffer[], const char *Value);
uint32_t writeBool(char Buffer[], bool Value);
uint32_t readUInt8(const char Buffer[], uint8_t &Value);
uint32_t readUInt16(const char Buffer[], uint16_t &Value);
uint32_t readUInt32(const char Buffer[], uint32_t &Value);
uint32_t readUInt64(const char Buffer[], uint64_t &Value);
uint32_t readUInt64as32(const char Buffer[], uint32_t &Value);
uint32_t readAddr(const char Buffer[], uint32_t &Value);
uint32_t readSize(const char Buffer[], uint32_t &Value);
uint32_t readString(const char Buffer[], char *const Value, uint32_t &Size);

#endif // EZ_SERIALIZE_H
58 changes: 58 additions & 0 deletions include/ez/support.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#ifndef EZ_SUPPORT_H
#define EZ_SUPPORT_H

#include <cstddef>
#include <cstdint>

#ifndef __has_builtin
#define __has_builtin(x) 0
#endif

#ifndef __has_feature
#define __has_feature(x) 0
#endif

#if __has_builtin(__builtin_unreachable)
# define EZ_BUILTIN_UNREACHABLE __builtin_unreachable()
#elif (__GNUC__ >= 4 && __GNUC_MINOR__ >= 5)
# define EZ_BUILTIN_UNREACHABLE __builtin_unreachable()
#else
# define EZ_BUILTIN_UNREACHABLE
#endif

#if __has_feature(cxx_attributes)
# define EZ_NORETURN [[noreturn]]
#elif defined(__GNUC__)
# define EZ_NORETURN __attribute__((noreturn))
#else
# define EZ_NORETURN
#endif

inline char *addr2ptr(uint32_t Addr) {
return reinterpret_cast<char *>(static_cast<uintptr_t>(Addr));
}

template <typename T>
uint32_t ptr2addr(T *Ptr) {
return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(Ptr));
}

// Return true if the argument is a power of two > 0
constexpr inline bool is_power_of_2(uint32_t Value) {
return Value && !(Value & (Value - 1));
}

template <uint32_t Align, typename T>
static T *align_ptr(T *Ptr) {
constexpr uint32_t Mask = Align - 1;
static_assert(is_power_of_2(Align), "Alignment must be a power of 2");
return addr2ptr(ptr2addr(Ptr + Mask) & ~Mask);
}

// Determine the size of a C array at compile-time
template <typename T, size_t sizeOfArray>
constexpr unsigned c_array_size(T (&)[sizeOfArray]) {
return sizeOfArray;
}

#endif // EZ_SUPPORT_H
17 changes: 17 additions & 0 deletions include/ez/symbols.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#ifndef EZ_SYMBOLS_H
#define EZ_SYMBOLS_H

#include <cstdint>

struct Symbol {
const char *Name;
uint32_t Addr;
operator bool() const { return Name != nullptr && Addr != 0; }
};

uint32_t getBootstrapSymbols(const Symbol *BootstrapSyms[]);

uint32_t lookupBuiltinSymbol(const char *Data, uint32_t Length);
uint32_t lookupSymbol(const char *Data, uint32_t Length);

#endif // EZ_SYMBOLS_H
Loading

0 comments on commit 9334235

Please sign in to comment.