Commit f0f978d2 authored by Alastair Robertson's avatar Alastair Robertson

Add cast_type to SizedType class

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