Commit f0f978d2 authored by Alastair Robertson's avatar Alastair Robertson

Add cast_type to SizedType class

parent 6f90769a
...@@ -23,8 +23,6 @@ public: ...@@ -23,8 +23,6 @@ public:
Map *map = nullptr; // Only set when this expression is assigned to a map Map *map = nullptr; // Only set when this expression is assigned to a map
bool is_literal = false; bool is_literal = false;
bool is_variable = false; bool is_variable = false;
bool is_map = false;
bool is_cast = false;
}; };
using ExpressionList = std::vector<Expression *>; using ExpressionList = std::vector<Expression *>;
...@@ -64,10 +62,8 @@ public: ...@@ -64,10 +62,8 @@ public:
class Map : public Expression { class Map : public Expression {
public: public:
explicit Map(std::string &ident) : ident(ident), vargs(nullptr) { is_map = true; } explicit Map(std::string &ident) : ident(ident), vargs(nullptr) { }
Map(std::string &ident, ExpressionList *vargs) : ident(ident), vargs(vargs) { Map(std::string &ident, ExpressionList *vargs) : ident(ident), vargs(vargs) { }
is_map = true;
}
std::string ident; std::string ident;
ExpressionList *vargs; ExpressionList *vargs;
...@@ -111,9 +107,7 @@ public: ...@@ -111,9 +107,7 @@ public:
class Cast : public Expression { class Cast : public Expression {
public: public:
Cast(const std::string &type, Expression *expr) : cast_type(type), expr(expr) { Cast(const std::string &type, Expression *expr) : cast_type(type), expr(expr) { }
is_cast = true;
}
std::string cast_type; std::string cast_type;
Expression *expr; Expression *expr;
......
...@@ -270,11 +270,27 @@ void SemanticAnalyser::visit(Unop &unop) ...@@ -270,11 +270,27 @@ void SemanticAnalyser::visit(Unop &unop)
{ {
unop.expr->accept(*this); unop.expr->accept(*this);
if (is_final_pass() && unop.expr->type.type != Type::integer) { if (is_final_pass() &&
err_ << "The " << opstr(unop) << " operator can not be used on expressions of type " << unop.expr->type << std::endl; unop.expr->type.type != Type::integer &&
unop.expr->type.type != Type::cast) {
err_ << "The " << opstr(unop) << " operator can not be used on expressions of type '"
<< unop.expr->type << "'" << std::endl;
} }
unop.type = SizedType(Type::integer, 8); if (unop.op == Parser::token::MUL && unop.expr->type.type == Type::cast) {
std::string cast_type = unop.expr->type.cast_type;
if (cast_type.back() == '*') {
cast_type.pop_back();
unop.type = SizedType(Type::cast, 8, cast_type);
}
else {
err_ << "Can not dereference struct/union of type '" << cast_type << "'. "
<< "It is not a pointer." << std::endl;
}
}
else {
unop.type = SizedType(Type::integer, 8);
}
} }
void SemanticAnalyser::visit(FieldAccess &acc) void SemanticAnalyser::visit(FieldAccess &acc)
...@@ -290,21 +306,12 @@ void SemanticAnalyser::visit(FieldAccess &acc) ...@@ -290,21 +306,12 @@ void SemanticAnalyser::visit(FieldAccess &acc)
return; return;
} }
std::string cast_type; std::string cast_type = acc.expr->type.cast_type;
if (acc.expr->is_variable) { if (cast_type.back() == '*') {
auto var = static_cast<Variable*>(acc.expr); err_ << "Can not access field '" << acc.field << "' on type '"
cast_type = variable_casts_[var->ident]; << cast_type << "'. Try dereferencing it first, or using '->'"
} << std::endl;
else if (acc.expr->is_map) { return;
auto map = static_cast<Map*>(acc.expr);
cast_type = map_casts_[map->ident];
}
else if (acc.expr->is_cast) {
auto cast = static_cast<Cast*>(acc.expr);
cast_type = cast->cast_type;
}
else {
abort();
} }
auto fields = bpftrace_.structs_[cast_type].fields; auto fields = bpftrace_.structs_[cast_type].fields;
...@@ -320,11 +327,23 @@ void SemanticAnalyser::visit(FieldAccess &acc) ...@@ -320,11 +327,23 @@ void SemanticAnalyser::visit(FieldAccess &acc)
void SemanticAnalyser::visit(Cast &cast) void SemanticAnalyser::visit(Cast &cast)
{ {
cast.expr->accept(*this); cast.expr->accept(*this);
cast.type = SizedType(Type::cast, cast.expr->type.size);
if (bpftrace_.structs_.count(cast.cast_type) == 0) { std::string cast_type = cast.cast_type;
err_ << "Unknown struct/union: '" << cast.cast_type << "'" << std::endl; if (cast_type.back() == '*')
cast_type.pop_back();
if (bpftrace_.structs_.count(cast_type) == 0) {
err_ << "Unknown struct/union: '" << cast_type << "'" << std::endl;
return;
}
int cast_size;
if (cast.cast_type.back() == '*') {
cast_size = sizeof(uintptr_t);
}
else {
cast_size = bpftrace_.structs_[cast.cast_type].size;
} }
cast.type = SizedType(Type::cast, cast_size, cast.cast_type);
} }
void SemanticAnalyser::visit(ExprStatement &expr) void SemanticAnalyser::visit(ExprStatement &expr)
...@@ -362,16 +381,16 @@ void SemanticAnalyser::visit(AssignMapStatement &assignment) ...@@ -362,16 +381,16 @@ void SemanticAnalyser::visit(AssignMapStatement &assignment)
} }
if (assignment.expr->type.type == Type::cast) { if (assignment.expr->type.type == Type::cast) {
auto cast = static_cast<Cast*>(assignment.expr); std::string cast_type = assignment.expr->type.cast_type;
if (map_casts_.count(map_ident) > 0 && std::string curr_cast_type = map_val_[map_ident].cast_type;
map_casts_[map_ident] != cast->cast_type) { if (curr_cast_type != "" && curr_cast_type != cast_type) {
err_ << "Type mismatch for " << map_ident << ": "; err_ << "Type mismatch for " << map_ident << ": ";
err_ << "trying to assign value of type '" << cast->cast_type; err_ << "trying to assign value of type '" << cast_type;
err_ << "'\n\twhen map already contains a value of type '"; err_ << "'\n\twhen map already contains a value of type '";
err_ << map_casts_[map_ident] << "'\n" << std::endl; err_ << curr_cast_type << "'\n" << std::endl;
} }
else { else {
map_casts_[map_ident] = cast->cast_type; map_val_[map_ident].cast_type = cast_type;
} }
} }
} }
...@@ -406,16 +425,16 @@ void SemanticAnalyser::visit(AssignVarStatement &assignment) ...@@ -406,16 +425,16 @@ void SemanticAnalyser::visit(AssignVarStatement &assignment)
} }
if (assignment.expr->type.type == Type::cast) { if (assignment.expr->type.type == Type::cast) {
auto cast = static_cast<Cast*>(assignment.expr); std::string cast_type = assignment.expr->type.cast_type;
if (variable_casts_.count(var_ident) > 0 && std::string curr_cast_type = variable_val_[var_ident].cast_type;
variable_casts_[var_ident] != cast->cast_type) { if (curr_cast_type != "" && curr_cast_type != cast_type) {
err_ << "Type mismatch for " << var_ident << ": "; err_ << "Type mismatch for " << var_ident << ": ";
err_ << "trying to assign value of type '" << cast->cast_type; err_ << "trying to assign value of type '" << cast_type;
err_ << "'\n\twhen variable already contains a value of type '"; err_ << "'\n\twhen variable already contains a value of type '";
err_ << variable_casts_[var_ident] << "'\n" << std::endl; err_ << curr_cast_type << "'\n" << std::endl;
} }
else { else {
variable_casts_[var_ident] = cast->cast_type; variable_val_[var_ident].cast_type = cast_type;
} }
} }
} }
...@@ -484,7 +503,6 @@ void SemanticAnalyser::visit(Probe &probe) ...@@ -484,7 +503,6 @@ void SemanticAnalyser::visit(Probe &probe)
{ {
// Clear out map of variable names - variables should be probe-local // Clear out map of variable names - variables should be probe-local
variable_val_.clear(); variable_val_.clear();
variable_casts_.clear();
probe_ = &probe; probe_ = &probe;
for (AttachPoint *ap : *probe.attach_points) { for (AttachPoint *ap : *probe.attach_points) {
......
...@@ -49,13 +49,12 @@ private: ...@@ -49,13 +49,12 @@ private:
const int num_passes_ = 10; const int num_passes_ = 10;
bool is_final_pass() const; bool is_final_pass() const;
std::string get_cast_type(Expression *expr);
Probe *probe_; Probe *probe_;
std::map<std::string, SizedType> variable_val_; std::map<std::string, SizedType> variable_val_;
std::map<std::string, SizedType> map_val_; std::map<std::string, SizedType> map_val_;
std::map<std::string, MapKey> map_key_; std::map<std::string, MapKey> map_key_;
std::map<std::string, std::string> variable_casts_;
std::map<std::string, std::string> map_casts_;
bool needs_stackid_map_ = false; bool needs_stackid_map_ = false;
bool has_begin_probe_ = false; bool has_begin_probe_ = false;
bool has_end_probe_ = false; bool has_end_probe_ = false;
......
...@@ -32,9 +32,11 @@ class SizedType ...@@ -32,9 +32,11 @@ class SizedType
{ {
public: public:
SizedType() : type(Type::none), size(0) { } SizedType() : type(Type::none), size(0) { }
SizedType(Type type, size_t size) : type(type), size(size) { } SizedType(Type type, size_t size, const std::string &cast_type = "")
: type(type), size(size), cast_type(cast_type) { }
Type type; Type type;
size_t size; size_t size;
std::string cast_type;
bool operator==(const SizedType &t) const; bool operator==(const SizedType &t) const;
}; };
......
...@@ -42,8 +42,13 @@ void test(const std::string &input, int expected_result=0) ...@@ -42,8 +42,13 @@ void test(const std::string &input, int expected_result=0)
{ {
Field field = { SizedType(Type::integer, 8), 0 }; Field field = { SizedType(Type::integer, 8), 0 };
Field mystr = { SizedType(Type::string, 8), 8 }; Field mystr = { SizedType(Type::string, 8), 8 };
Field type2_field_ptr = { SizedType(Type::cast, 8, "type2*"), 16 };
Field type2_field = { SizedType(Type::cast, 8, "type2"), 24 };
Struct type1 = { 16, {{"field", field}, { "mystr", mystr}} }; Struct type1 = { 16, {{"field", field},
{"mystr", mystr},
{"type2ptr", type2_field_ptr},
{"type2", type2_field}} };
Struct type2 = { 8, {{"field", field}} }; Struct type2 = { 8, {{"field", field}} };
BPFtrace bpftrace; BPFtrace bpftrace;
...@@ -367,6 +372,23 @@ TEST(semantic_analyser, field_access_types) ...@@ -367,6 +372,23 @@ TEST(semantic_analyser, field_access_types)
test("kprobe:f { ((type1)0).mystr == ((type2)0).field }", 10); test("kprobe:f { ((type1)0).mystr == ((type2)0).field }", 10);
} }
TEST(semantic_analyser, field_access_pointer)
{
test("kprobe:f { ((type1*)0)->field }", 0);
test("kprobe:f { ((type1*)0).field }", 1);
test("kprobe:f { *((type1*)0) }", 0);
}
TEST(semantic_analyser, field_access_sub_struct)
{
test("kprobe:f { ((type1)0).type2ptr->field }", 0);
test("kprobe:f { ((type1)0).type2.field }", 0);
test("kprobe:f { $x = (type2)0; $x = ((type1)0).type2 }", 0);
test("kprobe:f { $x = (type2*)0; $x = ((type1)0).type2ptr }", 0);
test("kprobe:f { $x = (type1)0; $x = ((type1)0).type2 }", 1);
test("kprobe:f { $x = (type1*)0; $x = ((type1)0).type2ptr }", 1);
}
} // 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