Skip to content

Commit

Permalink
Add bswap instructions
Browse files Browse the repository at this point in the history
Fixes #531

Signed-off-by: Dave Thaler <[email protected]>
  • Loading branch information
dthaler authored and elazarg committed Dec 29, 2023
1 parent 10d47ff commit 3321c60
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 11 deletions.
19 changes: 16 additions & 3 deletions src/asm_marshal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,14 @@ static uint8_t imm(Un::Op op) {
switch (op) {
case Op::NEG: return 0;
case Op::BE16:
case Op::LE16: return 16;
case Op::LE16:
case Op::SWAP16: return 16;
case Op::BE32:
case Op::LE32: return 32;
case Op::LE32:
case Op::SWAP32: return 32;
case Op::BE64:
case Op::LE64: return 64;
case Op::LE64:
case Op::SWAP64: return 64;
}
assert(false);
return {};
Expand Down Expand Up @@ -156,6 +159,16 @@ struct MarshalVisitor {
.offset = 0,
.imm = imm(b.op),
}};
case Un::Op::SWAP16:
case Un::Op::SWAP32:
case Un::Op::SWAP64:
return {ebpf_inst{
.opcode = static_cast<uint8_t>(INST_CLS_ALU64 | (0xd << 4)),
.dst = b.dst.v,
.src = 0,
.offset = 0,
.imm = imm(b.op),
}};
}
assert(false);
return {};
Expand Down
3 changes: 3 additions & 0 deletions src/asm_ostream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,9 @@ struct InstructionPrinterVisitor {
case Un::Op::LE16: os_ << "le16 "; break;
case Un::Op::LE32: os_ << "le32 "; break;
case Un::Op::LE64: os_ << "le64 "; break;
case Un::Op::SWAP16: os_ << "swap16 "; break;
case Un::Op::SWAP32: os_ << "swap32 "; break;
case Un::Op::SWAP64: os_ << "swap64 "; break;
case Un::Op::NEG: os_ << "-"; break;
}
os_ << b.dst;
Expand Down
5 changes: 4 additions & 1 deletion src/asm_parse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ using crab::linear_expression_t;
#define OPASSIGN R"_(\s*(\S*)=\s*)_"
#define ASSIGN R"_(\s*=\s*)_"
#define LONGLONG R"_(\s*(ll|)\s*)_"
#define UNOP R"_((-|be16|be32|be64|le16|le32|le64))_"
#define UNOP R"_((-|be16|be32|be64|le16|le32|le64|swap16|swap32|swap64))_"

#define PLUSMINUS R"_((\s*[+-])\s*)_"
#define LPAREN R"_(\s*\(\s*)_"
Expand Down Expand Up @@ -69,6 +69,9 @@ static const std::map<std::string, Un::Op> str_to_unop = {
{"le16", Un::Op::LE16},
{"le32", Un::Op::LE32},
{"le64", Un::Op::LE64},
{"swap16", Un::Op::SWAP16},
{"swap32", Un::Op::SWAP32},
{"swap64", Un::Op::SWAP64},
{"-", Un::Op::NEG},
};

Expand Down
3 changes: 3 additions & 0 deletions src/asm_syntax.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ struct Un {
LE16, // dst = htole16(dst)
LE32, // dst = htole32(dst)
LE64, // dst = htole64(dst)
SWAP16, // dst = bswap16(dst)
SWAP32, // dst = bswap32(dst)
SWAP64, // dst = bswap64(dst)
NEG, // dst = -dst
};

Expand Down
11 changes: 8 additions & 3 deletions src/asm_unmarshal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,14 @@ struct Unmarshaller {
return Bin::Op::ARSH;
case INST_ALU_OP_END:
if ((inst.opcode & INST_CLS_MASK) == INST_CLS_ALU64) {
std::string error_message =
"invalid endian immediate " + std::to_string(inst.imm) + " for 64 bit instruction";
throw InvalidInstruction(pc, error_message.c_str());
if (inst.opcode & INST_END_BE)
throw InvalidInstruction(pc, "invalid endian immediate");
switch (inst.imm) {
case 16: return Un::Op::SWAP16;
case 32: return Un::Op::SWAP32;
case 64: return Un::Op::SWAP64;
default: throw InvalidInstruction(pc, "invalid endian immediate");
}
}
switch (inst.imm) {
case 16: return (inst.opcode & INST_END_BE) ? Un::Op::BE16 : Un::Op::LE16;
Expand Down
12 changes: 12 additions & 0 deletions src/crab/ebpf_domain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1484,6 +1484,18 @@ void ebpf_domain_t::operator()(const Un& stmt) {
swap_endianness(dst.svalue, int64_t(0), boost::endian::native_to_little<int64_t>);
swap_endianness(dst.svalue, uint64_t(0), boost::endian::native_to_little<uint64_t>);
break;
case Un::Op::SWAP16:
swap_endianness(dst.svalue, uint16_t(0), boost::endian::endian_reverse<uint16_t>);
swap_endianness(dst.uvalue, uint16_t(0), boost::endian::endian_reverse<uint16_t>);
break;
case Un::Op::SWAP32:
swap_endianness(dst.svalue, uint32_t(0), boost::endian::endian_reverse<uint32_t>);
swap_endianness(dst.uvalue, uint32_t(0), boost::endian::endian_reverse<uint32_t>);
break;
case Un::Op::SWAP64:
swap_endianness(dst.svalue, int64_t(0), boost::endian::endian_reverse<int64_t>);
swap_endianness(dst.uvalue, uint64_t(0), boost::endian::endian_reverse<uint64_t>);
break;
case Un::Op::NEG:
neg(dst.svalue, dst.uvalue, stmt.is64 ? 64 : 32);
havoc_offsets(stmt.dst);
Expand Down
4 changes: 2 additions & 2 deletions src/test/test_marshal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,6 @@ TEST_CASE("fail unmarshal", "[disasm][marshal]") {
check_unmarshal_fail(ebpf_inst{.opcode = INST_CLS_JMP32}, "0: jump out of bounds\n");
check_unmarshal_fail(ebpf_inst{.opcode = 0x90 | INST_CLS_JMP32}, "0: Bad instruction\n");
check_unmarshal_fail(ebpf_inst{.opcode = 0x10 | INST_CLS_JMP32}, "0: jump out of bounds\n");
check_unmarshal_fail(ebpf_inst{.opcode = INST_ALU_OP_END | INST_CLS_ALU64, .imm = 0}, "0: invalid endian immediate 0 for 64 bit instruction\n");
check_unmarshal_fail(ebpf_inst{.opcode = INST_ALU_OP_END | INST_CLS_ALU64, .imm = 16}, "0: invalid endian immediate 16 for 64 bit instruction\n");
check_unmarshal_fail(ebpf_inst{.opcode = INST_ALU_OP_END | INST_CLS_ALU, .imm = 0}, "0: invalid endian immediate\n");
check_unmarshal_fail(ebpf_inst{.opcode = INST_ALU_OP_END | INST_CLS_ALU64, .imm = 0}, "0: invalid endian immediate\n");
}
44 changes: 42 additions & 2 deletions test-data/unop.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,16 @@ code:
post: ["r1.type=number", "r1.svalue=2396871057337221120", "r1.uvalue=2396871057337221120"]
---
test-case: be16 range

pre: ["r1.type=number", "r1.svalue=[0, 2]", "r1.uvalue=[0, 2]", "r1.svalue=r1.uvalue"]

code:
<start>: |
r1 = be16 r1 ; [0x0000, 0x0002] -> [0x0000, 0x2000] but currently we just lose the range
post: ["r1.type=number"]
---
test-case: le16 singleton

pre: ["r1.type=number", "r1.svalue=6636321", "r1.uvalue=6636321"]
Expand Down Expand Up @@ -111,12 +121,42 @@ code:
post: ["r1.type=number"]
---
test-case: be16 range
test-case: swap16 singleton

pre: ["r1.type=number", "r1.svalue=6636321", "r1.uvalue=6636321"]

code:
<start>: |
r1 = swap16 r1 ; 0x654321 -> 0x2143
post: ["r1.type=number", "r1.svalue=8515", "r1.uvalue=8515"]
---
test-case: swap32 singleton

pre: ["r1.type=number", "r1.svalue=40926266145", "r1.uvalue=40926266145"]

code:
<start>: |
r1 = swap32 r1 ; 0x0987654321 -> 0x21436587
post: ["r1.type=number", "r1.svalue=558065031", "r1.uvalue=558065031"]
---
test-case: swap64 singleton

pre: ["r1.type=number", "r1.svalue=40926266145", "r1.uvalue=40926266145"]

code:
<start>: |
r1 = swap64 r1 ; 0x0987654321 -> 0x2143658709000000
post: ["r1.type=number", "r1.svalue=2396871057337221120", "r1.uvalue=2396871057337221120"]
---
test-case: swap16 range

pre: ["r1.type=number", "r1.svalue=[0, 2]", "r1.uvalue=[0, 2]", "r1.svalue=r1.uvalue"]

code:
<start>: |
r1 = be16 r1 ; [0x0000, 0x0002] -> [0x0000, 0x2000] but currently we just lose the range
r1 = swap16 r1 ; [0x0000, 0x0002] -> [0x0000, 0x2000] but currently we just lose the range
post: ["r1.type=number"]

0 comments on commit 3321c60

Please sign in to comment.