Commit e1f8fd51 authored by Alastair Robertson's avatar Alastair Robertson

Semantic analyser: Add type checking for field accesses

parent 1e047247
#include <iostream>
#include "semantic_analyser.h" #include "semantic_analyser.h"
#include "ast.h" #include "ast.h"
#include "fake_map.h" #include "fake_map.h"
...@@ -312,6 +310,9 @@ void SemanticAnalyser::visit(FieldAccess &acc) ...@@ -312,6 +310,9 @@ void SemanticAnalyser::visit(FieldAccess &acc)
err_ << "Struct/union of type '" << cast_type << "' does not contain " err_ << "Struct/union of type '" << cast_type << "' does not contain "
<< "a field named '" << acc.field << "'" << std::endl; << "a field named '" << acc.field << "'" << std::endl;
} }
else {
acc.type = std::get<0>(fields[acc.field]);
}
} }
void SemanticAnalyser::visit(Cast &cast) void SemanticAnalyser::visit(Cast &cast)
......
#pragma once #pragma once
#include <iostream>
#include <sstream> #include <sstream>
#include "ast.h" #include "ast.h"
......
...@@ -30,7 +30,8 @@ public: ...@@ -30,7 +30,8 @@ public:
std::map<std::string, std::unique_ptr<IMap>> maps_; std::map<std::string, std::unique_ptr<IMap>> maps_;
std::map<std::string, std::tuple<uint8_t *, uintptr_t>> sections_; std::map<std::string, std::tuple<uint8_t *, uintptr_t>> sections_;
std::map<std::string, std::map<std::string, int>> structs_; // structs_ = { struct_name: { field_name: { sized_type, offset } } }
std::map<std::string, std::map<std::string, std::tuple<SizedType, int>>> structs_;
std::vector<std::tuple<std::string, std::vector<SizedType>>> printf_args_; std::vector<std::tuple<std::string, std::vector<SizedType>>> printf_args_;
std::unique_ptr<IMap> stackid_map_; std::unique_ptr<IMap> stackid_map_;
std::unique_ptr<IMap> perf_event_map_; std::unique_ptr<IMap> perf_event_map_;
......
...@@ -41,6 +41,9 @@ void test(Driver &driver, const std::string &input, int expected_result=0) ...@@ -41,6 +41,9 @@ void test(Driver &driver, const std::string &input, int expected_result=0)
void test(const std::string &input, int expected_result=0) void test(const std::string &input, int expected_result=0)
{ {
BPFtrace bpftrace; BPFtrace bpftrace;
bpftrace.structs_["type1"]["field"] = std::make_tuple(SizedType(Type::integer, 8), 0);
bpftrace.structs_["type1"]["mystr"] = std::make_tuple(SizedType(Type::string, 8), 8);
bpftrace.structs_["type2"]["field"] = std::make_tuple(SizedType(Type::integer, 8), 0);
Driver driver; Driver driver;
test(bpftrace, driver, input, expected_result); test(bpftrace, driver, input, expected_result);
} }
...@@ -302,36 +305,24 @@ TEST(semantic_analyser, profile) ...@@ -302,36 +305,24 @@ TEST(semantic_analyser, profile)
TEST(semantic_analyser, variable_cast_types) TEST(semantic_analyser, variable_cast_types)
{ {
BPFtrace bpftrace; test("kprobe:f { $x = (type1)cpu; $x = (type1)cpu; }", 0);
bpftrace.structs_["type1"]["field"] = 0; test("kprobe:f { $x = (type1)cpu; $x = (type2)cpu; }", 1);
bpftrace.structs_["type2"]["field"] = 0;
test(bpftrace, "kprobe:f { $x = (type1)cpu; $x = (type1)cpu; }", 0);
test(bpftrace, "kprobe:f { $x = (type1)cpu; $x = (type2)cpu; }", 1);
} }
TEST(semantic_analyser, map_cast_types) TEST(semantic_analyser, map_cast_types)
{ {
BPFtrace bpftrace; test("kprobe:f { @x = (type1)cpu; @x = (type1)cpu; }", 0);
bpftrace.structs_["type1"]["field"] = 0; test("kprobe:f { @x = (type1)cpu; @x = (type2)cpu; }", 1);
bpftrace.structs_["type2"]["field"] = 0;
test(bpftrace, "kprobe:f { @x = (type1)cpu; @x = (type1)cpu; }", 0);
test(bpftrace, "kprobe:f { @x = (type1)cpu; @x = (type2)cpu; }", 1);
} }
TEST(semantic_analyser, variable_casts_are_local) TEST(semantic_analyser, variable_casts_are_local)
{ {
BPFtrace bpftrace; test("kprobe:f { $x = (type1)cpu } kprobe:g { $x = (type2)cpu; }", 0);
bpftrace.structs_["type1"]["field"] = 0;
bpftrace.structs_["type2"]["field"] = 0;
test(bpftrace, "kprobe:f { $x = (type1)cpu } kprobe:g { $x = (type2)cpu; }", 0);
} }
TEST(semantic_analyser, map_casts_are_global) TEST(semantic_analyser, map_casts_are_global)
{ {
BPFtrace bpftrace; test("kprobe:f { @x = (type1)cpu } kprobe:g { @x = (type2)cpu; }", 1);
bpftrace.structs_["type1"]["field"] = 0;
bpftrace.structs_["type2"]["field"] = 0;
test(bpftrace, "kprobe:f { @x = (type1)cpu } kprobe:g { @x = (type2)cpu; }", 1);
} }
TEST(semantic_analyser, cast_unknown_type) TEST(semantic_analyser, cast_unknown_type)
...@@ -341,20 +332,16 @@ TEST(semantic_analyser, cast_unknown_type) ...@@ -341,20 +332,16 @@ TEST(semantic_analyser, cast_unknown_type)
TEST(semantic_analyser, field_access) TEST(semantic_analyser, field_access)
{ {
BPFtrace bpftrace; test("kprobe:f { ((type1)cpu).field }", 0);
bpftrace.structs_["type1"]["field"] = 0; test("kprobe:f { $x = (type1)cpu; $x.field }", 0);
test(bpftrace, "kprobe:f { ((type1)cpu).field }", 0); test("kprobe:f { @x = (type1)cpu; @x.field }", 0);
test(bpftrace, "kprobe:f { $x = (type1)cpu; $x.field }", 0);
test(bpftrace, "kprobe:f { @x = (type1)cpu; @x.field }", 0);
} }
TEST(semantic_analyser, field_access_wrong_field) TEST(semantic_analyser, field_access_wrong_field)
{ {
BPFtrace bpftrace; test("kprobe:f { ((type1)cpu).blah }", 1);
bpftrace.structs_["type1"]["field"] = 0; test("kprobe:f { $x = (type1)cpu; $x.blah }", 1);
test(bpftrace, "kprobe:f { ((type1)cpu).blah }", 1); test("kprobe:f { @x = (type1)cpu; @x.blah }", 1);
test(bpftrace, "kprobe:f { $x = (type1)cpu; $x.blah }", 1);
test(bpftrace, "kprobe:f { @x = (type1)cpu; @x.blah }", 1);
} }
TEST(semantic_analyser, field_access_wrong_expr) TEST(semantic_analyser, field_access_wrong_expr)
...@@ -362,6 +349,18 @@ TEST(semantic_analyser, field_access_wrong_expr) ...@@ -362,6 +349,18 @@ TEST(semantic_analyser, field_access_wrong_expr)
test("kprobe:f { 1234->field }", 1); test("kprobe:f { 1234->field }", 1);
} }
TEST(semantic_analyser, field_access_types)
{
test("kprobe:f { ((type1)0).field == 123 }", 0);
test("kprobe:f { ((type1)0).field == \"abc\" }", 10);
test("kprobe:f { ((type1)0).mystr == \"abc\" }", 0);
test("kprobe:f { ((type1)0).mystr == 123 }", 10);
test("kprobe:f { ((type1)0).field == ((type2)0).field }", 0);
test("kprobe:f { ((type1)0).mystr == ((type2)0).field }", 10);
}
} // namespace semantic_analyser } // namespace semantic_analyser
} // namespace test } // namespace test
} // namespace bpftrace } // namespace bpftrace
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment