Remove Linux + parcon dependency (#906)
* Remove Linux + parcon dependency Signed-off-by: Alan Jowett <alanjo@microsoft.com> * Remove Linux + parcon dependency Signed-off-by: Alan Jowett <alanjo@microsoft.com> * Set path to compiler Signed-off-by: Alan Jowett <alanjo@microsoft.com> * Fix the build Signed-off-by: Alan Jowett <alanjo@microsoft.com> * Fix build Signed-off-by: Alan Jowett <alanjo@microsoft.com> * PR feedbac Signed-off-by: Alan Jowett <alanjo@microsoft.com> * PR feedback Signed-off-by: Alan Jowett <alanjo@microsoft.com>
This commit is contained in:
Родитель
59716dfa16
Коммит
b06f6ac820
|
@ -13,49 +13,54 @@ permissions:
|
|||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
configurations: [Debug, Release]
|
||||
runs-on: windows-2019
|
||||
env:
|
||||
# Path to the solution file relative to the root of the project.
|
||||
SOLUTION_FILE_PATH: ebpf-for-windows.sln
|
||||
|
||||
# Configuration type to build.
|
||||
# You can convert this to a build matrix if you need coverage of multiple configuration types.
|
||||
# https://docs.github.com/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
|
||||
BUILD_CONFIGURATION: ${{matrix.configurations}}
|
||||
|
||||
BUILD_PLATFORM: x64
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@9b0655f430fba8c7001d4e38f8d4306db5c6e0ab
|
||||
with:
|
||||
egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs
|
||||
|
||||
- uses: actions/checkout@b0e28b5ac45a892f91e7d036f8200cf5ed489415
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Install Dependencies
|
||||
working-directory: ${{env.GITHUB_WORKSPACE}}
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install python3 python3-pip python3-setuptools python3-wheel nuget
|
||||
python3 -m pip install external/parcon
|
||||
python3 -m pip install --require-hash -r tests/bpf2c_tests/requirements.txt
|
||||
- name: Add MSBuild to PATH
|
||||
uses: microsoft/setup-msbuild@becb80cf9a036187bb1e07e74eb64e25850d757a
|
||||
|
||||
- name: Restore nuget packages
|
||||
- name: Install Tools
|
||||
working-directory: ${{env.GITHUB_WORKSPACE}}
|
||||
run: |
|
||||
nuget restore
|
||||
choco install -y --requirechecksum=true --checksum=2295A733DA39412C61E4F478677519DD0BB1893D88313CE56B468C9E50517888 --checksum-type=sha256 OpenCppCoverage
|
||||
echo "C:\Program Files\OpenCppCoverage" >> $env:GITHUB_PATH
|
||||
|
||||
- name: Fix include folder
|
||||
- name: Create catch2 project
|
||||
working-directory: ${{env.GITHUB_WORKSPACE}}
|
||||
run: |
|
||||
rm -rf include/asm include/linux
|
||||
cmake -G "Visual Studio 16 2019" -S external\catch2 -B external\catch2\build -DBUILD_TESTING=OFF
|
||||
|
||||
- name: Build & run tests
|
||||
- name: Build
|
||||
working-directory: ${{env.GITHUB_WORKSPACE}}
|
||||
run: msbuild /m /p:Configuration=${{env.BUILD_CONFIGURATION}} /p:Platform=${{env.BUILD_PLATFORM}} ${{env.SOLUTION_FILE_PATH}} /target:tests\bpf2c_tests
|
||||
|
||||
# Run bpf2c_tests.exe.exe and generate ebpf_for_windows.xml
|
||||
- name: Generate Report - bpf2c Tests
|
||||
shell: cmd
|
||||
run: |
|
||||
export CXXFLAGS="--coverage -g -O0"
|
||||
cd tests/bpf2c_tests
|
||||
make
|
||||
./bpf2c_tests -s
|
||||
gcovr -r ../.. --cobertura ../../bpf2c.xml --gcov-ignore-parse-errors
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat"
|
||||
OpenCppCoverage.exe --sources %CD% --excluded_sources %CD%\external\Catch2 --export_type cobertura:ebpf_for_windows_%BUILD_CONFIGURATION%.xml --working_dir %BUILD_PLATFORM%\%BUILD_CONFIGURATION% -- %BUILD_PLATFORM%\%BUILD_CONFIGURATION%\bpf2c_tests.exe -s
|
||||
|
||||
- name: Upload Report to Codecov
|
||||
uses: codecov/codecov-action@f32b3a3741e1053eb607407145bc9619351dc93b
|
||||
with:
|
||||
files: bpf2c.xml
|
||||
files: ebpf_for_windows_${{env.BUILD_CONFIGURATION}}.xml
|
||||
fail_ci_if_error: true
|
||||
functionalities: fix
|
||||
|
||||
|
|
|
@ -16,6 +16,3 @@
|
|||
[submodule "external/Catch2"]
|
||||
path = external/Catch2
|
||||
url = https://github.com/catchorg/Catch2.git
|
||||
[submodule "external/parcon"]
|
||||
path = external/parcon
|
||||
url = https://github.com/javawizard/parcon.git
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 1e4e5422c1339658fd0977998ae811662307bc46
|
|
@ -1,13 +0,0 @@
|
|||
# Copyright (c) Microsoft Corporation
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
FLAGS = $(CXXFLAGS) -Wall -g -std=c++17 -fPIE -Wno-unknown-pragmas
|
||||
|
||||
CC = g++
|
||||
INCLUDES = -I../../include -I../../packages/CatchOrg.Catch.2.8.0/lib/native/include -I../../external/ubpf/vm -I../../external/ebpf-verifier/external/ELFIO -I../../tools/bpf2c/ -I../../tests/libs/util
|
||||
|
||||
bpf2c_tests: ../../tools/bpf2c/bpf_code_generator.cpp raw_bpf.cpp ../../tools/bpf2c/btf_parser.cpp
|
||||
${CC} ${FLAGS} ${INCLUDES} $^ -o $@
|
||||
|
||||
clean:
|
||||
rm -f *.o bpf2c_tests *.data.* *.data
|
|
@ -4,7 +4,6 @@
|
|||
SPDX-License-Identifier: MIT
|
||||
-->
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\packages\CatchOrg.Catch.2.8.0\build\native\CatchOrg.Catch.props" Condition="Exists('..\..\packages\CatchOrg.Catch.2.8.0\build\native\CatchOrg.Catch.props')" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
|
@ -141,16 +140,14 @@
|
|||
<FileType>CppCode</FileType>
|
||||
</CopyFileToFolders>
|
||||
<ClCompile Include="..\..\tools\bpf2c\btf_parser.cpp" />
|
||||
<ClCompile Include="bpf_assembler.cpp" />
|
||||
<ClCompile Include="raw_bpf.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Makefile" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\tools\bpf2c\bpf_code_generator.h" />
|
||||
<ClInclude Include="..\..\tools\bpf2c\btf.h" />
|
||||
<ClInclude Include="..\..\tools\bpf2c\btf_parser.h" />
|
||||
<ClInclude Include="bpf_assembler.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\external\Catch2\build\src\Catch2WithMain.vcxproj">
|
||||
|
@ -159,10 +156,4 @@
|
|||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\packages\CatchOrg.Catch.2.8.0\build\native\CatchOrg.Catch.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\CatchOrg.Catch.2.8.0\build\native\CatchOrg.Catch.props'))" />
|
||||
</Target>
|
||||
</Project>
|
|
@ -28,10 +28,9 @@
|
|||
<ClCompile Include="..\..\tools\bpf2c\btf_parser.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
<None Include="Makefile" />
|
||||
<ClCompile Include="bpf_assembler.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\tools\bpf2c\bpf_code_generator.h">
|
||||
|
@ -43,6 +42,9 @@
|
|||
<ClInclude Include="..\..\tools\bpf2c\btf_parser.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="bpf_assembler.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CopyFileToFolders Include="bpf_test.cpp">
|
||||
|
|
|
@ -0,0 +1,382 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <variant>
|
||||
#include <sstream>
|
||||
|
||||
#include "bpf_assembler.h"
|
||||
|
||||
typedef std::variant<ebpf_inst, std::array<ebpf_inst, 2>> bpf_encode_result_t;
|
||||
|
||||
typedef std::function<bpf_encode_result_t(const std::string& mnemonic, const std::vector<std::string>& operands)>
|
||||
bpf_encode_t;
|
||||
|
||||
static const std::unordered_map<std::string, int> _bpf_encode_register_map{
|
||||
{"r0", 0},
|
||||
{"r1", 1},
|
||||
{"r2", 2},
|
||||
{"r3", 3},
|
||||
{"r4", 4},
|
||||
{"r5", 5},
|
||||
{"r6", 6},
|
||||
{"r7", 7},
|
||||
{"r8", 8},
|
||||
{"r9", 9},
|
||||
{"r10", 10},
|
||||
};
|
||||
|
||||
static const std::unordered_map<std::string, int> _bpf_encode_alu_ops{
|
||||
{"add", 0x0},
|
||||
{"sub", 0x1},
|
||||
{"mul", 0x2},
|
||||
{"div", 0x3},
|
||||
{"or", 0x4},
|
||||
{"and", 0x5},
|
||||
{"lsh", 0x6},
|
||||
{"rsh", 0x7},
|
||||
{"neg", 0x8},
|
||||
{"mod", 0x9},
|
||||
{"xor", 0xa},
|
||||
{"mov", 0xb},
|
||||
{"arsh", 0xc},
|
||||
{"le", 0xd},
|
||||
{"be", 0xd},
|
||||
};
|
||||
|
||||
static const std::unordered_map<std::string, int> _bpf_encode_jmp_ops{
|
||||
{"jeq", 0x1},
|
||||
{"jgt", 0x2},
|
||||
{"jge", 0x3},
|
||||
{"jset", 0x4},
|
||||
{"jne", 0x5},
|
||||
{"jsgt", 0x6},
|
||||
{"jsge", 0x7},
|
||||
{"jlt", 0xa},
|
||||
{"jle", 0xb},
|
||||
{"jslt", 0xc},
|
||||
{"jsle", 0xd},
|
||||
};
|
||||
|
||||
static uint64_t
|
||||
_decode_imm64(const std::string& str)
|
||||
{
|
||||
if (str.find("0x") == std::string::npos) {
|
||||
return std::stoull(str);
|
||||
} else {
|
||||
return std::stoull(str, nullptr, 16);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
_decode_imm32(const std::string& str)
|
||||
{
|
||||
if (str.find("0x") == std::string::npos) {
|
||||
return std::stoul(str);
|
||||
} else {
|
||||
return std::stoul(str, nullptr, 16);
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
_decode_offset(const std::string& str)
|
||||
{
|
||||
if (str.find("0x") == std::string::npos) {
|
||||
return static_cast<uint16_t>(std::stoul(str));
|
||||
} else {
|
||||
return static_cast<uint16_t>(std::stoul(str, nullptr, 16));
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
_decode_register(const std::string& register_name)
|
||||
{
|
||||
auto reg = _bpf_encode_register_map.find(register_name);
|
||||
if (reg == _bpf_encode_register_map.end()) {
|
||||
throw std::runtime_error(std::string("Invalid register: ") + register_name);
|
||||
}
|
||||
return static_cast<uint8_t>(reg->second);
|
||||
}
|
||||
|
||||
static std::tuple<uint8_t, uint16_t>
|
||||
_decode_register_and_offset(const std::string& operand)
|
||||
{
|
||||
auto reg_start = operand.find('[');
|
||||
auto reg_end = operand.find('+');
|
||||
reg_end = (reg_end != std::string::npos) ? reg_end : operand.find('-');
|
||||
reg_end = (reg_end != std::string::npos) ? reg_end : operand.find(']');
|
||||
|
||||
if (reg_start == std::string::npos || reg_end == std::string::npos) {
|
||||
throw std::runtime_error(std::string("Invalid operand: ") + operand);
|
||||
}
|
||||
|
||||
if (operand.substr(reg_end).starts_with(']')) {
|
||||
return std::make_tuple<uint8_t, uint16_t>(
|
||||
_decode_register(operand.substr(reg_start + 1, reg_end - reg_start - 1)), 0);
|
||||
} else {
|
||||
return std::make_tuple<uint8_t, uint16_t>(
|
||||
_decode_register(operand.substr(reg_start + 1, reg_end - reg_start - 1)),
|
||||
_decode_offset(operand.substr(reg_end)));
|
||||
}
|
||||
}
|
||||
|
||||
static bpf_encode_result_t
|
||||
_encode_ld(const std::string& mnemonic, const std::vector<std::string>& operands)
|
||||
{
|
||||
std::array<ebpf_inst, 2> inst{};
|
||||
if (mnemonic != "lddw") {
|
||||
throw std::runtime_error(std::string("Invalid mnemonic: ") + mnemonic);
|
||||
}
|
||||
if (operands.size() != 2) {
|
||||
throw std::runtime_error(std::string("Wrong operand count: ") + mnemonic);
|
||||
}
|
||||
inst[0].opcode = EBPF_OP_LDDW;
|
||||
inst[0].dst = _decode_register(operands[0]);
|
||||
uint64_t immediate = _decode_imm64(operands[1]);
|
||||
inst[0].imm = static_cast<uint32_t>(immediate);
|
||||
inst[1].imm = static_cast<uint32_t>(immediate >> 32);
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
||||
static bpf_encode_result_t
|
||||
_encode_ldx(const std::string& mnemonic, const std::vector<std::string>& operands)
|
||||
{
|
||||
ebpf_inst inst{};
|
||||
if (operands.size() != 2) {
|
||||
throw std::runtime_error(std::string("Wrong operand count: ") + mnemonic);
|
||||
}
|
||||
inst.dst = _decode_register(operands[0]);
|
||||
auto [src, offset] = _decode_register_and_offset(operands[1]);
|
||||
inst.src = src;
|
||||
inst.offset = offset;
|
||||
if (mnemonic == "ldxb") {
|
||||
inst.opcode = EBPF_OP_LDXB;
|
||||
} else if (mnemonic == "ldxdw") {
|
||||
inst.opcode = EBPF_OP_LDXDW;
|
||||
} else if (mnemonic == "ldxh") {
|
||||
inst.opcode = EBPF_OP_LDXH;
|
||||
} else if (mnemonic == "ldxw") {
|
||||
inst.opcode = EBPF_OP_LDXW;
|
||||
} else {
|
||||
throw std::runtime_error(std::string("Invalid mnemonic: ") + mnemonic);
|
||||
}
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
||||
static bpf_encode_result_t
|
||||
_encode_st(const std::string& mnemonic, const std::vector<std::string>& operands)
|
||||
{
|
||||
ebpf_inst inst{};
|
||||
if (operands.size() != 2) {
|
||||
throw std::runtime_error(std::string("Wrong operand count: ") + mnemonic);
|
||||
}
|
||||
auto [dst, offset] = _decode_register_and_offset(operands[0]);
|
||||
inst.dst = dst;
|
||||
inst.offset = offset;
|
||||
if (mnemonic == "stb") {
|
||||
inst.opcode = EBPF_OP_STB;
|
||||
} else if (mnemonic == "stdw") {
|
||||
inst.opcode = EBPF_OP_STDW;
|
||||
} else if (mnemonic == "sth") {
|
||||
inst.opcode = EBPF_OP_STH;
|
||||
} else if (mnemonic == "stw") {
|
||||
inst.opcode = EBPF_OP_STW;
|
||||
} else {
|
||||
throw std::runtime_error(std::string("Invalid mnemonic: ") + mnemonic);
|
||||
}
|
||||
inst.imm = _decode_imm32(operands[1]);
|
||||
return inst;
|
||||
}
|
||||
|
||||
static bpf_encode_result_t
|
||||
_encode_stx(const std::string& mnemonic, const std::vector<std::string>& operands)
|
||||
{
|
||||
ebpf_inst inst{};
|
||||
if (operands.size() != 2) {
|
||||
throw std::runtime_error(std::string("Wrong operand count: ") + mnemonic);
|
||||
}
|
||||
auto [dst, offset] = _decode_register_and_offset(operands[0]);
|
||||
inst.dst = dst;
|
||||
inst.offset = offset;
|
||||
inst.src = _decode_register(operands[1]);
|
||||
if (mnemonic == "stxb") {
|
||||
inst.opcode = EBPF_OP_STXB;
|
||||
} else if (mnemonic == "stxdw") {
|
||||
inst.opcode = EBPF_OP_STXDW;
|
||||
} else if (mnemonic == "stxh") {
|
||||
inst.opcode = EBPF_OP_STXH;
|
||||
} else if (mnemonic == "stxw") {
|
||||
inst.opcode = EBPF_OP_STXW;
|
||||
} else {
|
||||
throw std::runtime_error(std::string("Invalid mnemonic: ") + mnemonic);
|
||||
}
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
||||
static bpf_encode_result_t
|
||||
_encode_alu(const std::string& mnemonic, const std::vector<std::string>& operands)
|
||||
{
|
||||
ebpf_inst inst{};
|
||||
std::string alu_op;
|
||||
if (mnemonic.starts_with("be")) {
|
||||
if (operands.size() != 1) {
|
||||
throw std::runtime_error(std::string("Wrong operand count: ") + mnemonic);
|
||||
}
|
||||
inst.opcode = EBPF_OP_BE;
|
||||
inst.dst = _decode_register(operands[0]);
|
||||
inst.imm = _decode_imm32(mnemonic.substr(2));
|
||||
return inst;
|
||||
} else if (mnemonic.starts_with("le")) {
|
||||
if (operands.size() != 1) {
|
||||
throw std::runtime_error(std::string("Wrong operand count: ") + mnemonic);
|
||||
}
|
||||
inst.opcode = EBPF_OP_LE;
|
||||
inst.dst = _decode_register(operands[0]);
|
||||
inst.imm = _decode_imm32(mnemonic.substr(2));
|
||||
return inst;
|
||||
}
|
||||
|
||||
if (mnemonic.starts_with("neg")) {
|
||||
if (operands.size() != 1) {
|
||||
throw std::runtime_error(std::string("Wrong operand count: ") + mnemonic);
|
||||
}
|
||||
} else {
|
||||
if (operands.size() != 2) {
|
||||
throw std::runtime_error(std::string("Wrong operand count: ") + mnemonic);
|
||||
}
|
||||
}
|
||||
|
||||
if (mnemonic.ends_with("32")) {
|
||||
inst.opcode |= EBPF_CLS_ALU;
|
||||
alu_op = mnemonic.substr(0, mnemonic.size() - 2);
|
||||
} else {
|
||||
inst.opcode |= EBPF_CLS_ALU64;
|
||||
alu_op = mnemonic;
|
||||
}
|
||||
auto iter = _bpf_encode_alu_ops.find(alu_op);
|
||||
if (iter == _bpf_encode_alu_ops.end()) {
|
||||
throw std::runtime_error(std::string("Invalid mnemonic: ") + mnemonic);
|
||||
}
|
||||
inst.opcode |= iter->second << 4;
|
||||
|
||||
inst.dst = _decode_register(operands[0]);
|
||||
|
||||
if (operands.size() == 2) {
|
||||
if (operands[1].starts_with('r')) {
|
||||
inst.opcode |= EBPF_SRC_REG;
|
||||
inst.src = _decode_register(operands[1]);
|
||||
} else {
|
||||
inst.opcode |= EBPF_SRC_IMM;
|
||||
inst.imm = _decode_imm32(operands[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return inst;
|
||||
}
|
||||
|
||||
static bpf_encode_result_t
|
||||
_encode_jmp(const std::string& mnemonic, const std::vector<std::string>& operands)
|
||||
{
|
||||
ebpf_inst inst{};
|
||||
inst.opcode |= EBPF_CLS_JMP;
|
||||
if (mnemonic == "ja") {
|
||||
if (operands.size() != 1) {
|
||||
throw std::runtime_error(std::string("Wrong operand count: ") + mnemonic);
|
||||
}
|
||||
|
||||
inst.offset = _decode_offset(operands[0]);
|
||||
} else if (mnemonic == "exit") {
|
||||
if (operands.size() != 0) {
|
||||
throw std::runtime_error(std::string("Wrong operand count: ") + mnemonic);
|
||||
}
|
||||
inst.opcode = EBPF_OP_EXIT;
|
||||
} else if (mnemonic == "call") {
|
||||
if (operands.size() != 1) {
|
||||
throw std::runtime_error(std::string("Wrong operand count: ") + mnemonic);
|
||||
}
|
||||
inst.opcode = EBPF_OP_CALL;
|
||||
inst.imm = _decode_imm32(operands[0]);
|
||||
} else {
|
||||
if (operands.size() != 3) {
|
||||
throw std::runtime_error(std::string("Wrong operand count: ") + mnemonic);
|
||||
}
|
||||
auto iter = _bpf_encode_jmp_ops.find(mnemonic);
|
||||
inst.opcode |= iter->second << 4;
|
||||
inst.dst = _decode_register(operands[0]);
|
||||
if (operands[1].starts_with('r')) {
|
||||
inst.opcode |= EBPF_SRC_REG;
|
||||
inst.src = _decode_register(operands[1]);
|
||||
} else {
|
||||
inst.opcode |= EBPF_SRC_IMM;
|
||||
inst.imm = _decode_imm32(operands[1]);
|
||||
}
|
||||
inst.offset = _decode_offset(operands[2]);
|
||||
}
|
||||
return inst;
|
||||
}
|
||||
|
||||
static const std::unordered_map<std::string, bpf_encode_t> _bpf_mnemonic_map{
|
||||
{"add", _encode_alu}, {"add32", _encode_alu}, {"and", _encode_alu}, {"and32", _encode_alu},
|
||||
{"arsh", _encode_alu}, {"arsh32", _encode_alu}, {"be16", _encode_alu}, {"be32", _encode_alu},
|
||||
{"be64", _encode_alu}, {"call", _encode_jmp}, {"div", _encode_alu}, {"div32", _encode_alu},
|
||||
{"exit", _encode_jmp}, {"ja", _encode_jmp}, {"jeq", _encode_jmp}, {"jge", _encode_jmp},
|
||||
{"jgt", _encode_jmp}, {"jle", _encode_jmp}, {"jlt", _encode_jmp}, {"jne", _encode_jmp},
|
||||
{"jset", _encode_jmp}, {"jsge", _encode_jmp}, {"jsgt", _encode_jmp}, {"jsle", _encode_jmp},
|
||||
{"jslt", _encode_jmp}, {"lddw", _encode_ld}, {"ldxb", _encode_ldx}, {"ldxdw", _encode_ldx},
|
||||
{"ldxh", _encode_ldx}, {"ldxw", _encode_ldx}, {"le16", _encode_alu}, {"le32", _encode_alu},
|
||||
{"le64", _encode_alu}, {"lsh", _encode_alu}, {"lsh32", _encode_alu}, {"mod", _encode_alu},
|
||||
{"mod32", _encode_alu}, {"mov", _encode_alu}, {"mov32", _encode_alu}, {"mul", _encode_alu},
|
||||
{"mul32", _encode_alu}, {"neg", _encode_alu}, {"neg32", _encode_alu}, {"or", _encode_alu},
|
||||
{"or32", _encode_alu}, {"rsh", _encode_alu}, {"rsh32", _encode_alu}, {"stb", _encode_st},
|
||||
{"stdw", _encode_st}, {"sth", _encode_st}, {"stw", _encode_st}, {"stxb", _encode_stx},
|
||||
{"stxdw", _encode_stx}, {"stxh", _encode_stx}, {"stxw", _encode_stx}, {"sub", _encode_alu},
|
||||
{"sub32", _encode_alu}, {"xor", _encode_alu}, {"xor32", _encode_alu},
|
||||
};
|
||||
|
||||
std::vector<ebpf_inst>
|
||||
bpf_assembler(std::istream& input)
|
||||
{
|
||||
std::vector<ebpf_inst> output;
|
||||
std::string line;
|
||||
// Parse the input stream one line at a time.
|
||||
while (std::getline(input, line)) {
|
||||
std::istringstream line_stream(line);
|
||||
std::string mnemonic;
|
||||
std::string operand;
|
||||
std::vector<std::string> operands;
|
||||
// Check for empty lines.
|
||||
if (!std::getline(line_stream, mnemonic, ' ')) {
|
||||
continue;
|
||||
}
|
||||
// Split the line on ' '
|
||||
while (std::getline(line_stream, operand, ' ')) {
|
||||
if (operand.starts_with('#')) {
|
||||
break;
|
||||
}
|
||||
if (operand.ends_with(',')) {
|
||||
operand = operand.substr(0, operand.length() - 1);
|
||||
}
|
||||
operands.emplace_back(operand);
|
||||
}
|
||||
// Find the handler for this mnemonic.
|
||||
auto iter = _bpf_mnemonic_map.find(mnemonic);
|
||||
if (iter == _bpf_mnemonic_map.end()) {
|
||||
throw std::runtime_error(std::string("Invalid mnemonic: ") + mnemonic);
|
||||
}
|
||||
// Invoke handler and store result.
|
||||
auto result = iter->second(mnemonic, operands);
|
||||
if (std::holds_alternative<ebpf_inst>(result)) {
|
||||
output.emplace_back(std::get<ebpf_inst>(result));
|
||||
} else {
|
||||
for (const auto& inst : std::get<std::array<ebpf_inst, 2>>(result)) {
|
||||
output.emplace_back(inst);
|
||||
}
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include "ebpf.h"
|
||||
|
||||
/**
|
||||
* @brief Accept an input stream containing BPF instructions and return a vector of ebpf_inst.
|
||||
*
|
||||
* @param[in] input Input stream containing BPF instructions to assemble.
|
||||
* @return Vector of ebpf_inst
|
||||
*/
|
||||
std::vector<ebpf_inst>
|
||||
bpf_assembler(std::istream& input);
|
|
@ -37,18 +37,8 @@ memfrob(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e)
|
|||
};
|
||||
|
||||
static uint64_t
|
||||
trash_registers(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e)
|
||||
no_op(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e)
|
||||
{
|
||||
/* Overwrite all caller-save registers */
|
||||
asm("mov $0xf0, %rax;"
|
||||
"mov $0xf1, %rcx;"
|
||||
"mov $0xf2, %rdx;"
|
||||
"mov $0xf3, %rsi;"
|
||||
"mov $0xf4, %rdi;"
|
||||
"mov $0xf5, %r8;"
|
||||
"mov $0xf6, %r9;"
|
||||
"mov $0xf7, %r10;"
|
||||
"mov $0xf8, %r11;");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -73,7 +63,7 @@ unwind(uint64_t a, uint64_t b, uint64_t c, uint64_t d, uint64_t e)
|
|||
std::map<uint32_t, uint64_t (*)(uint64_t r1, uint64_t r2, uint64_t r3, uint64_t r4, uint64_t r5)> helper_functions = {
|
||||
{0, gather_bytes},
|
||||
{1, memfrob},
|
||||
{2, trash_registers},
|
||||
{2, no_op},
|
||||
{3, sqrti},
|
||||
{4, strcmp_ext},
|
||||
{5, unwind},
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="CatchOrg.Catch" version="2.8.0" targetFramework="native" />
|
||||
</packages>
|
|
@ -4,18 +4,33 @@
|
|||
#define CATCH_CONFIG_MAIN
|
||||
|
||||
#include "bpf_code_generator.h"
|
||||
#define NUGET_CATCH
|
||||
#include "catch_wrapper.hpp"
|
||||
#include "bpf_assembler.h"
|
||||
|
||||
#define SEPERATOR "/"
|
||||
#define CC "g++"
|
||||
#define CXXFLAG "-g -O2"
|
||||
#define EXT ".out"
|
||||
#define PYTHON "python3"
|
||||
#define SEPARATOR "\\"
|
||||
|
||||
std::string
|
||||
env_or_default(const char* environment_variable, const char* default_value)
|
||||
{
|
||||
std::string return_value = default_value;
|
||||
char* buffer = nullptr;
|
||||
size_t buffer_size = 0;
|
||||
if (_dupenv_s(&buffer, &buffer_size, environment_variable) == 0) {
|
||||
if (buffer != nullptr) {
|
||||
return_value = buffer;
|
||||
}
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
void
|
||||
run_test(const std::string& data_file)
|
||||
{
|
||||
std::string cc = env_or_default("CC", "cl.exe");
|
||||
std::string cxxflags = env_or_default("CXXFLAGS", "/EHsc /nologo");
|
||||
|
||||
enum class _state
|
||||
{
|
||||
state_ignore,
|
||||
|
@ -24,11 +39,9 @@ run_test(const std::string& data_file)
|
|||
state_result,
|
||||
state_memory,
|
||||
} state = _state::state_ignore;
|
||||
std::string prefix = data_file.substr(data_file.find_last_of(SEPERATOR) + 1);
|
||||
std::string prefix = data_file.substr(data_file.find_last_of(SEPARATOR) + 1);
|
||||
|
||||
std::string temp_asm_name = std::string(prefix) + ".asm";
|
||||
|
||||
std::ofstream data_out(temp_asm_name);
|
||||
std::stringstream data_out;
|
||||
std::ifstream data_in(data_file);
|
||||
|
||||
std::string result;
|
||||
|
@ -84,31 +97,17 @@ run_test(const std::string& data_file)
|
|||
continue;
|
||||
}
|
||||
}
|
||||
data_out.flush();
|
||||
data_out.close();
|
||||
|
||||
if (result.find("0x") != std::string::npos) {
|
||||
result = result.substr(result.find("0x") + 2);
|
||||
}
|
||||
|
||||
std::string assembler_command = std::string(PYTHON " .." SEPERATOR ".." SEPERATOR "external" SEPERATOR
|
||||
"ubpf" SEPERATOR "bin" SEPERATOR "ubpf-assembler <") +
|
||||
std::string(temp_asm_name) + std::string(" >") + std::string(prefix) +
|
||||
std::string(".bc");
|
||||
REQUIRE(system(assembler_command.c_str()) == 0);
|
||||
|
||||
std::ifstream bytcode_in(std::string(prefix) + std::string(".bc"), std::ios_base::in | std::ios_base::binary);
|
||||
std::vector<ebpf_inst> program;
|
||||
ebpf_inst instruction;
|
||||
while (bytcode_in.read(reinterpret_cast<char*>(&instruction), sizeof(instruction))) {
|
||||
program.push_back(instruction);
|
||||
}
|
||||
bytcode_in.close();
|
||||
data_out.seekg(0);
|
||||
auto intstructions = bpf_assembler(data_out);
|
||||
|
||||
std::ofstream c_file(std::string(prefix) + std::string(".c"));
|
||||
try {
|
||||
|
||||
bpf_code_generator code("test", program);
|
||||
bpf_code_generator code("test", intstructions);
|
||||
code.generate("test");
|
||||
code.emit_c_code(c_file);
|
||||
} catch (std::runtime_error& err) {
|
||||
|
@ -117,12 +116,12 @@ run_test(const std::string& data_file)
|
|||
c_file.flush();
|
||||
c_file.close();
|
||||
|
||||
std::string compile_command = std::string(CC " " CXXFLAG " -I.." SEPERATOR ".." SEPERATOR "include ") +
|
||||
std::string(prefix) + std::string(".c ") + std::string(" bpf_test.cpp >") +
|
||||
std::string(prefix) + std::string(".log -o ") + std::string(prefix) +
|
||||
std::string(EXT);
|
||||
std::string compile_command = cc + std::string(" ") + cxxflags +
|
||||
std::string(" -I.." SEPARATOR ".." SEPARATOR "include ") + std::string(prefix) +
|
||||
std::string(".c ") + std::string(" bpf_test.cpp >") + std::string(prefix) +
|
||||
std::string(".log");
|
||||
REQUIRE(system(compile_command.c_str()) == 0);
|
||||
std::string test_command = std::string("." SEPERATOR) + std::string(prefix) + std::string(EXT) + std::string(" ") +
|
||||
std::string test_command = std::string("." SEPARATOR) + std::string(prefix) + std::string(" ") +
|
||||
std::string(result) + std::string(" \"") + std::string(mem) + std::string("\"");
|
||||
REQUIRE(system(test_command.c_str()) == 0);
|
||||
}
|
||||
|
@ -130,7 +129,7 @@ run_test(const std::string& data_file)
|
|||
#define DECLARE_TEST(FILE) \
|
||||
TEST_CASE(FILE, "[raw_bpf_code_gen]") \
|
||||
{ \
|
||||
run_test(".." SEPERATOR ".." SEPERATOR "external" SEPERATOR "ubpf" SEPERATOR "tests" SEPERATOR "" FILE \
|
||||
run_test(".." SEPARATOR ".." SEPARATOR "external" SEPARATOR "ubpf" SEPARATOR "tests" SEPARATOR "" FILE \
|
||||
".data"); \
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
# Copyright (c) Microsoft Corporation
|
||||
# SPDX-License-Identifier: MIT
|
||||
nose == 1.3.1 --hash=sha256:85273b87ab3db9307e3b1452b071e25c1db1cc812bc337d2a97ea0b0cf2ab6ba
|
||||
pyelftools == 0.27 --hash=sha256:5609aa6da1123fccfae2e8431a67b4146aa7fad5b3889f808df12b110f230937
|
||||
gcovr == 5.1 --hash=sha256:8bff85699d6a41057831bc3c201d9801d174da2800f8c403b0e6e831fe7936f3
|
||||
lxml == 4.8.0 --hash=sha256:ce13d6291a5f47c1c8dbd375baa78551053bc6b5e5c0e9bb8e39c0a8359fd52f
|
Загрузка…
Ссылка в новой задаче