Skip to content

Commit

Permalink
string positional parameter in comparison failure
Browse files Browse the repository at this point in the history
Now it is possible to compare 2 string variables. I was not able to get the string size so the byte code is quite large. The old comparison between a static string and a variable still the same.
fixes: #450
  • Loading branch information
williangaspar committed Mar 27, 2019
1 parent 49ff42b commit 7c8e8ed
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 21 deletions.
43 changes: 26 additions & 17 deletions src/ast/codegen_llvm.cpp
Expand Up @@ -753,28 +753,37 @@ void CodegenLLVM::visit(Binop &binop)
Type &type = binop.left->type.type;
if (type == Type::string)
{
Value *val;

if (binop.op != bpftrace::Parser::token::EQ && binop.op != bpftrace::Parser::token::NE) {
std::cerr << "missing codegen to string operator \"" << opstr(binop) << "\"" << std::endl;
abort();
}

std::string string_literal("");
if (binop.right->is_literal) {

bool inverse = binop.op == bpftrace::Parser::token::NE;

if (binop.right->is_literal)
{
binop.left->accept(*this);
val = expr_;
string_literal = reinterpret_cast<String*>(binop.right)->str;
} else {
string_literal = static_cast<String *>(binop.right)->str;
expr_ = b_.CreateStrcmp(expr_, string_literal, inverse);
}
else if (binop.left->is_literal)
{
binop.right->accept(*this);
val = expr_;
string_literal = reinterpret_cast<String*>(binop.left)->str;
string_literal = static_cast<String *>(binop.left)->str;
expr_ = b_.CreateStrcmp(expr_, string_literal, inverse);
}
else
{
binop.right->accept(*this);
Value * right_string = expr_;

switch (binop.op) {
case bpftrace::Parser::token::EQ:
expr_ = b_.CreateStrcmp(val, string_literal);
break;
case bpftrace::Parser::token::NE:
expr_ = b_.CreateStrcmp(val, string_literal, true);
break;
default:
std::cerr << "missing codegen to string operator \"" << opstr(binop) << "\"" << std::endl;
abort();
binop.left->accept(*this);
Value * left_string = expr_;

expr_ = b_.CreateStrcmp(left_string, right_string, inverse);
}
}
else
Expand Down
70 changes: 70 additions & 0 deletions src/ast/irbuilderbpf.cpp
Expand Up @@ -407,6 +407,76 @@ Value *IRBuilderBPF::CreateStrcmp(Value* val, std::string str, bool inverse) {
return result;
}

Value *IRBuilderBPF::CreateStrcmp(Value* val1, Value* val2, bool inverse) {
/*
// This function compares each character of the two string.
// It returns true if all are equal and false if any are different
// strcmp(String val1, String val2)
{
for (size_t i = 0; i < bpftrace_.strlen_; i++)
{
if (val1[i] != val2[i])
{
return false;
}
if (val1[i] == NULL)
{
return true;
}
}
return true;
}
*/
Function *parent = GetInsertBlock()->getParent();
BasicBlock *str_ne = BasicBlock::Create(module_.getContext(), "strcmp.false", parent);
AllocaInst *store = CreateAllocaBPF(getInt8Ty(), "strcmp.result");
BasicBlock *done = BasicBlock::Create(module_.getContext(), "strcmp.done", parent);

CreateStore(getInt1(inverse), store);

Value *null_byte = getInt8(0);

for (size_t i = 0; i < bpftrace_.strlen_; i++)
{
BasicBlock *char_eq = BasicBlock::Create(module_.getContext(), "strcmp.loop", parent);
BasicBlock *loop_null_check = BasicBlock::Create(module_.getContext(), "strcmp.loop_null_cmp", parent);

AllocaInst *val_char1 = CreateAllocaBPF(getInt8Ty(), "strcmp.char_l");
Value *ptr1 = CreateAdd(val1, getInt64(i));
CreateProbeRead(val_char1, 1, ptr1);
Value *l = CreateLoad(getInt8Ty(), val_char1);

AllocaInst *val_char2 = CreateAllocaBPF(getInt8Ty(), "strcmp.char_r");
Value *ptr2 = CreateAdd(val2, getInt64(i));
CreateProbeRead(val_char2, 1, ptr2);
Value *r = CreateLoad(getInt8Ty(), val_char2);

Value *cmp = CreateICmpNE(l, r, "strcmp.cmp");
CreateCondBr(cmp, str_ne, loop_null_check);

SetInsertPoint(loop_null_check);

Value *cmp_null = CreateICmpEQ(l, null_byte, "strcmp.cmp_null");
CreateCondBr(cmp_null, done, char_eq);

SetInsertPoint(char_eq);
}

CreateBr(done);
SetInsertPoint(done);
CreateStore(getInt1(!inverse), store);

CreateBr(str_ne);
SetInsertPoint(str_ne);

Value *result = CreateLoad(store);
CreateLifetimeEnd(store);

return result;
}

CallInst *IRBuilderBPF::CreateGetNs()
{
// u64 ktime_get_ns()
Expand Down
1 change: 1 addition & 0 deletions src/ast/irbuilderbpf.h
Expand Up @@ -46,6 +46,7 @@ class IRBuilderBPF : public IRBuilder<>
CallInst *CreateProbeReadStr(Value *dst, size_t size, Value *src);
Value *CreateUSDTReadArgument(Value *ctx, AttachPoint *attach_point, int arg_name, Builtin &builtin, int pid);
Value *CreateStrcmp(Value* val, std::string str, bool inverse=false);
Value *CreateStrcmp(Value* val1, Value* val2, bool inverse=false);
CallInst *CreateGetNs();
CallInst *CreateGetPidTgid();
CallInst *CreateGetCurrentCgroupId();
Expand Down
5 changes: 1 addition & 4 deletions src/ast/semantic_analyser.cpp
Expand Up @@ -540,10 +540,7 @@ void SemanticAnalyser::visit(Binop &binop)
err_ << "comparing '" << lhs << "' ";
err_ << "with '" << rhs << "'" << std::endl;
}
else if (lhs == Type::string && !(binop.left->is_literal || binop.right->is_literal)) {
err_ << "Comparison between two variables of ";
err_ << "type string is not allowed" << std::endl;
}

else if (lhs != Type::integer &&
binop.op != Parser::token::EQ &&
binop.op != Parser::token::NE) {
Expand Down
15 changes: 15 additions & 0 deletions tests/runtime/other
Expand Up @@ -42,3 +42,18 @@ NAME struct keyword optional when casting
RUN bpftrace -e 'struct Bar { int x; } struct Foo { struct Bar *bar; } i:ms:1 { $foo = (struct Foo *)0; @x = $foo->bar->x; exit()}'
EXPECT @x: 0
TIMEOUT 5

NAME struct positional string compare - equal returns true
RUN bpftrace -e 'BEGIN { if (str($1) == str($2)) { printf("I got %s\n", str($1));}; exit();}' "hello" "hello"
EXPECT I got hello
TIMEOUT 5

NAME struct positional string compare - equal returns false
RUN bpftrace -e 'BEGIN { if (str($1) == str($2)) { printf("I got %s\n", str($1));} else { printf("not equal\n");}; exit();}' "hi" "hello"
EXPECT not equal
TIMEOUT 5

NAME struct positional string compare - not equal
RUN bpftrace -e 'BEGIN { if (str($1) != str($2)) { printf("I got %s\n", str($1));} else { printf("not equal\n");}; exit();}' "hello" "hello"
EXPECT not equal
TIMEOUT 5

0 comments on commit 7c8e8ed

Please sign in to comment.