Commit fe88e5a2 authored by Brenden Blanco's avatar Brenden Blanco

Improve json type support for misc struct/union types

The ability of the clang rewriter to extract the type information for
some types of structs, unions, and pointers to the aforementioned was
somewhat buggy. This became exposed in a test_clang case after a user
upgraded to a newer kernel, wherein the struct definition changed. The
functionality in question is only used to pass json-ified representation
of the struct to python in order to program the Key/Leaf metaclass.

Improve support for this and other types, including unions.
Signed-off-by: default avatarBrenden Blanco <bblanco@plumgrid.com>
parent fbe34c99
...@@ -67,10 +67,7 @@ bool BMapDeclVisitor::VisitRecordDecl(RecordDecl *D) { ...@@ -67,10 +67,7 @@ bool BMapDeclVisitor::VisitRecordDecl(RecordDecl *D) {
result_ += "\", ["; result_ += "\", [";
for (auto F : D->getDefinition()->fields()) { for (auto F : D->getDefinition()->fields()) {
result_ += "["; result_ += "[";
if (F->getType()->isPointerType()) TraverseDecl(F);
result_ += "\"" + F->getName().str() + "\", \"unsigned long long\"";
else
TraverseDecl(F);
if (const ConstantArrayType *T = dyn_cast<ConstantArrayType>(F->getType())) if (const ConstantArrayType *T = dyn_cast<ConstantArrayType>(F->getType()))
result_ += ", [" + T->getSize().toString(10, false) + "]"; result_ += ", [" + T->getSize().toString(10, false) + "]";
if (F->isBitField()) if (F->isBitField())
...@@ -79,9 +76,19 @@ bool BMapDeclVisitor::VisitRecordDecl(RecordDecl *D) { ...@@ -79,9 +76,19 @@ bool BMapDeclVisitor::VisitRecordDecl(RecordDecl *D) {
} }
if (!D->getDefinition()->field_empty()) if (!D->getDefinition()->field_empty())
result_.erase(result_.end() - 2); result_.erase(result_.end() - 2);
result_ += "]]"; result_ += "]";
if (D->isUnion())
result_ += ", \"union\"";
else if (D->isStruct())
result_ += ", \"struct\"";
result_ += "]";
return true; return true;
} }
// pointer to anything should be treated as terminal, don't recurse further
bool BMapDeclVisitor::VisitPointerType(const PointerType *T) {
result_ += "\"unsigned long long\"";
return false;
}
bool BMapDeclVisitor::VisitTagType(const TagType *T) { bool BMapDeclVisitor::VisitTagType(const TagType *T) {
return TraverseDecl(T->getDecl()->getDefinition()); return TraverseDecl(T->getDecl()->getDefinition());
} }
...@@ -510,22 +517,32 @@ bool BTypeVisitor::VisitVarDecl(VarDecl *Decl) { ...@@ -510,22 +517,32 @@ bool BTypeVisitor::VisitVarDecl(VarDecl *Decl) {
sscanf(un.release, "%d.%d.", &major, &minor); sscanf(un.release, "%d.%d.", &major, &minor);
} }
TableDesc table; TableDesc table = {};
table.name = Decl->getName(); table.name = Decl->getName();
unsigned i = 0; unsigned i = 0;
for (auto F : RD->fields()) { for (auto F : RD->fields()) {
size_t sz = C.getTypeSize(F->getType()) >> 3; size_t sz = C.getTypeSize(F->getType()) >> 3;
if (F->getName() == "key") { if (F->getName() == "key") {
if (sz == 0) {
unsigned diag_id = C.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error,
"invalid zero-sized leaf");
C.getDiagnostics().Report(F->getLocStart(), diag_id);
return false;
}
table.key_size = sz; table.key_size = sz;
BMapDeclVisitor visitor(C, table.key_desc); BMapDeclVisitor visitor(C, table.key_desc);
if (!visitor.TraverseType(F->getType())) visitor.TraverseType(F->getType());
return false;
} else if (F->getName() == "leaf") { } else if (F->getName() == "leaf") {
if (sz == 0) {
unsigned diag_id = C.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error,
"invalid zero-sized leaf");
C.getDiagnostics().Report(F->getLocStart(), diag_id);
return false;
}
table.leaf_size = sz; table.leaf_size = sz;
BMapDeclVisitor visitor(C, table.leaf_desc); BMapDeclVisitor visitor(C, table.leaf_desc);
if (!visitor.TraverseType(F->getType())) visitor.TraverseType(F->getType());
return false;
} else if (F->getName() == "data") { } else if (F->getName() == "data") {
table.max_entries = sz / table.leaf_size; table.max_entries = sz / table.leaf_size;
} }
......
...@@ -49,6 +49,7 @@ class BMapDeclVisitor : public clang::RecursiveASTVisitor<BMapDeclVisitor> { ...@@ -49,6 +49,7 @@ class BMapDeclVisitor : public clang::RecursiveASTVisitor<BMapDeclVisitor> {
bool VisitBuiltinType(const clang::BuiltinType *T); bool VisitBuiltinType(const clang::BuiltinType *T);
bool VisitTypedefType(const clang::TypedefType *T); bool VisitTypedefType(const clang::TypedefType *T);
bool VisitTagType(const clang::TagType *T); bool VisitTagType(const clang::TagType *T);
bool VisitPointerType(const clang::PointerType *T);
private: private:
clang::ASTContext &C; clang::ASTContext &C;
std::string &result_; std::string &result_;
......
...@@ -518,7 +518,13 @@ class BPF(object): ...@@ -518,7 +518,13 @@ class BPF(object):
fields.append((t[0], BPF._decode_table_type(t[1]), t[2])) fields.append((t[0], BPF._decode_table_type(t[1]), t[2]))
else: else:
raise Exception("Failed to decode type %s" % str(t)) raise Exception("Failed to decode type %s" % str(t))
cls = type(str(desc[0]), (ct.Structure,), dict(_fields_=fields)) base = ct.Structure
if len(desc) > 2:
if desc[2] == u"union":
base = ct.Union
elif desc[2] == u"struct":
base = ct.Structure
cls = type(str(desc[0]), (base,), dict(_fields_=fields))
return cls return cls
def get_table(self, name, keytype=None, leaftype=None): def get_table(self, name, keytype=None, leaftype=None):
......
...@@ -247,7 +247,7 @@ int kprobe____kmalloc(struct pt_regs *ctx, size_t size) { ...@@ -247,7 +247,7 @@ int kprobe____kmalloc(struct pt_regs *ctx, size_t size) {
if (leaf) if (leaf)
leaf->size += size; leaf->size += size;
return 0; return 0;
}""", debug=4) }""")
def test_unop_probe_read(self): def test_unop_probe_read(self):
text = """ text = """
...@@ -263,5 +263,29 @@ int trace_entry(struct pt_regs *ctx, struct request *req) { ...@@ -263,5 +263,29 @@ int trace_entry(struct pt_regs *ctx, struct request *req) {
b = BPF(text=text) b = BPF(text=text)
fn = b.load_func("trace_entry", BPF.KPROBE) fn = b.load_func("trace_entry", BPF.KPROBE)
def test_complex_leaf_types(self):
text = """
struct list;
struct list {
struct list *selfp;
struct list *another_selfp;
struct list *selfp_array[2];
};
struct empty {
};
union emptyu {
struct empty *em1;
struct empty em2;
struct empty em3;
struct empty em4;
};
BPF_TABLE("array", int, struct list, t1, 1);
BPF_TABLE("array", int, struct list *, t2, 1);
BPF_TABLE("array", int, union emptyu, t3, 1);
"""
b = BPF(text=text)
import ctypes
self.assertEqual(ctypes.sizeof(b["t3"].Leaf), 8)
if __name__ == "__main__": if __name__ == "__main__":
main() main()
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