Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ workflows:
- build-gcc
oid_test_args: "-ftype-graph"
tests_regex: "OidIntegration\\..*"
exclude_regex: ".*inheritance_polymorphic.*"
- test:
name: test-typed-data-segment-gcc
requires:
Expand Down Expand Up @@ -57,7 +56,7 @@ workflows:
oid_test_args: "-ftype-graph"
tests_regex: "OidIntegration\\..*"
# Tests disabled due to bad DWARF generated by the old clang compiler in CI
exclude_regex: ".*inheritance_polymorphic.*|.*fbstring.*|.*std_string_*|.*multi_arg_tb_.*|.*ignored_a"
exclude_regex: ".*fbstring.*|.*std_string_*|.*multi_arg_tb_.*|.*ignored_a"

executors:
ubuntu-docker:
Expand Down
20 changes: 11 additions & 9 deletions oi/CodeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -366,11 +366,15 @@ void addStandardGetSizeFuncDefs(std::string& code) {
}
)";
}
} // namespace

void getClassSizeFuncDecl(const Class& c, std::string& code) {
void CodeGen::getClassSizeFuncDecl(const Class& c, std::string& code) const {
if (config_.features[Feature::PolymorphicInheritance] && c.isDynamic()) {
code += "void getSizeTypeConcrete(const " + c.name() +
" &t, size_t &returnArg);\n";
}
code += "void getSizeType(const " + c.name() + " &t, size_t &returnArg);\n";
}
} // namespace

/*
* Generates a getSizeType function for the given concrete class.
Expand Down Expand Up @@ -421,7 +425,7 @@ void CodeGen::getClassSizeFuncConcrete(std::string_view funcName,
code += "}\n";
}

void CodeGen::getClassSizeFuncDef(const Class& c, std::string& code) {
void CodeGen::getClassSizeFuncDef(const Class& c, std::string& code) const {
if (!config_.features[Feature::PolymorphicInheritance] || !c.isDynamic()) {
// Just directly use the concrete size function as this class' getSizeType()
getClassSizeFuncConcrete("getSizeType", c, code);
Expand All @@ -438,9 +442,7 @@ void CodeGen::getClassSizeFuncDef(const Class& c, std::string& code) {
if (childClass == nullptr) {
abort(); // TODO
}
// TODO:
// auto fqChildName = *fullyQualifiedName(child);
auto fqChildName = "TODO - implement me";
auto fqChildName = childClass->fqName();

// We must split this assignment and append because the C++ standard lacks
// an operator for concatenating std::string and std::string_view...
Expand Down Expand Up @@ -511,8 +513,10 @@ void getContainerSizeFuncDef(std::unordered_set<const ContainerInfo*>& used,
boost::format(c.containerInfo_.codegen.func) % c.containerInfo_.typeName;
code += fmt.str();
}
} // namespace

void addGetSizeFuncDecls(const TypeGraph& typeGraph, std::string& code) {
void CodeGen::addGetSizeFuncDecls(const TypeGraph& typeGraph,
std::string& code) const {
for (const Type& t : typeGraph.finalTypes) {
if (const auto* c = dynamic_cast<const Class*>(&t)) {
getClassSizeFuncDecl(*c, code);
Expand All @@ -522,8 +526,6 @@ void addGetSizeFuncDecls(const TypeGraph& typeGraph, std::string& code) {
}
}

} // namespace

void CodeGen::addGetSizeFuncDefs(const TypeGraph& typeGraph,
std::string& code) {
for (const Type& t : typeGraph.finalTypes) {
Expand Down
6 changes: 5 additions & 1 deletion oi/CodeGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,13 @@ class CodeGen {
thriftIssetMembers_;

void genDefsThrift(const type_graph::TypeGraph& typeGraph, std::string& code);
void addGetSizeFuncDecls(const type_graph::TypeGraph& typeGraph,
std::string& code) const;
void getClassSizeFuncDecl(const type_graph::Class& c,
std::string& code) const;
void addGetSizeFuncDefs(const type_graph::TypeGraph& typeGraph,
std::string& code);
void getClassSizeFuncDef(const type_graph::Class& c, std::string& code);
void getClassSizeFuncDef(const type_graph::Class& c, std::string& code) const;
void getClassSizeFuncConcrete(std::string_view funcName,
const type_graph::Class& c,
std::string& code) const;
Expand Down
63 changes: 26 additions & 37 deletions oi/type_graph/AddChildren.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,28 @@ void AddChildren::visit(Class& c) {
dynamic_cast<Class*>(&childType); // TODO don't use dynamic_cast
if (!childClass) // TODO dodgy error handling
abort();
c.children.push_back(*childClass);

// // Add recursive children to this class as well
// enumerateClassChildren(drgnChild, children);
/*
* Confirm that this child is actually our child.
*
* We previously used unqualified names for speed, so types with the same
* name in different namespaces would have been grouped together.
*/
bool isActuallyChild = false;
for (const auto& parent : childClass->parents) {
// TODO support parent containers?
auto* parentClass = dynamic_cast<Class*>(&stripTypedefs(parent.type()));
if (!parentClass)
continue;

if (parentClass->fqName() == c.fqName()) {
isActuallyChild = true;
break;
}
}

if (isActuallyChild)
c.children.push_back(*childClass);
}

// Recurse to find children-of-children
Expand All @@ -87,35 +105,6 @@ void AddChildren::visit(Class& c) {
}
}

// TODO how to flatten children of children?
// void AddChildren::enumerateClassChildren(struct drgn_type *type,
// std::vector<std::reference_wrapper<Class>> &children) {
// // This function is called recursively to find children-of-children, so the
// // "children" vector argument will not necessarily be empty.
//
// const char* tag = drgn_type_tag(type);
// if (tag == nullptr) {
// return;
// }
// auto it = childClasses_.find(tag);
// if (it == childClasses_.end()) {
// return;
// }
//
// const auto& drgnChildren = it->second;
// for (drgn_type* drgnChild : drgnChildren) {
// // TODO there shouldn't be any need for a dynamic cast here...
// Type *ttt = enumerateClass(drgnChild);
// auto *child = dynamic_cast<Class*>(ttt);
// if (!child)
// abort();
// children.push_back(*child);
//
// // Add recursive children to this class as well
// enumerateClassChildren(drgnChild, children);
// }
//}

void AddChildren::recordChildren(drgn_type* type) {
drgn_type_template_parameter* parents = drgn_type_parents(type);

Expand All @@ -141,20 +130,20 @@ void AddChildren::recordChildren(drgn_type* type) {
}

const char* parentName = drgn_type_tag(parent);
if (parentName == nullptr) {
// VLOG(1) << "No name for parent class (" << parent << ") of "
// << drgn_type_tag(type);
if (!parentName) {
continue;
}

/*
* drgn pointers are not stable, so use string representation for reverse
* mapping for now. We need to find a better way of creating this
* childClasses map - ideally drgn would do this for us.
*
* Use unqualified names because fully-qualified names are too slow. We'll
* check against fully-qualified names once we've narrowed down the number
* of types to compare.
*/
childClasses_[parentName].push_back(type);
// VLOG(1) << drgn_type_tag(type) << "(" << type << ") is a child of "
// << drgn_type_tag(parent) << "(" << parent << ")";
}
}

Expand Down
10 changes: 10 additions & 0 deletions oi/type_graph/AddChildren.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ class TypeGraph;
/*
* AddChildren
*
* Populates the "children" field of Class types.
*
* DWARF only stores a mapping of [child -> parent], but sometimes we want the
* invserse: [parent -> child]. We must iterate over every single type to build
* up our own inverse mapping, before applying it to the relevant type nodes.
*
* This is expensive and only useful for types which make use of dynamic
* inheritance hierarchies (e.g. polymorphism), so is not done as part of the
* standard DrgnParser stage.
*
* TODO
* what about children which inherit through a typedef? don't think that'll
* work yet
Expand Down
16 changes: 7 additions & 9 deletions oi/type_graph/Flattener.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,6 @@ void Flattener::accept(Type& type) {
}

namespace {
// TODO this function is a massive hack. don't do it like this please
Type& stripTypedefs(Type& type) {
Type* t = &type;
while (const Typedef* td = dynamic_cast<Typedef*>(t)) {
t = &td->underlyingType();
}
return *t;
}

void flattenParent(const Parent& parent,
std::vector<Member>& flattenedMembers) {
Type& parentType = stripTypedefs(parent.type());
Expand Down Expand Up @@ -205,6 +196,13 @@ void Flattener::visit(Class& c) {
for (const auto& child : c.children) {
accept(child);
}

// Pull in children from flattened children
// This may result in duplicates, but that shouldn't be a big deal
for (const Class& child : c.children) {
c.children.insert(c.children.end(), child.children.begin(),
child.children.end());
}
}

void Flattener::visit(Container& c) {
Expand Down
4 changes: 4 additions & 0 deletions oi/type_graph/NameGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ void NameGen::visit(Class& c) {
// Deduplicate member names. Duplicates may be present after flattening.
for (size_t i = 0; i < c.members.size(); i++) {
c.members[i].name += "_" + std::to_string(i);

// GCC includes dots in vptr member names, e.g. "_vptr.MyClass"
// These aren't valid in C++, so we must replace them
std::replace(c.members[i].name.begin(), c.members[i].name.end(), '.', '$');
}

for (const auto& param : c.templateParams) {
Expand Down
2 changes: 1 addition & 1 deletion oi/type_graph/Printer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ void Printer::print_function(const Function& function) {
void Printer::print_child(const Type& child) {
depth_++;
prefix();
out_ << "Child:" << std::endl;
out_ << "Child" << std::endl;
print(child);
depth_--;
}
Expand Down
9 changes: 9 additions & 0 deletions oi/type_graph/Types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,13 @@ bool Class::isDynamic() const {
return false;
}

// TODO this function is a massive hack. don't do it like this please
Type& stripTypedefs(Type& type) {
Type* t = &type;
while (const Typedef* td = dynamic_cast<Typedef*>(t)) {
t = &td->underlyingType();
}
return *t;
}

} // namespace type_graph
12 changes: 7 additions & 5 deletions oi/type_graph/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ class Class : public Type {
std::vector<Parent> parents; // Sorted by offset
std::vector<Member> members; // Sorted by offset
std::vector<Function> functions;
std::vector<std::reference_wrapper<Type>>
std::vector<std::reference_wrapper<Class>>
children; // Only for dynamic classes

private:
Expand Down Expand Up @@ -295,8 +295,8 @@ class Container : public Type {

class Enum : public Type {
public:
explicit Enum(const std::string& name, size_t size)
: name_(name), size_(size) {
explicit Enum(std::string name, size_t size)
: name_(std::move(name)), size_(size) {
}

DECLARE_ACCEPT
Expand Down Expand Up @@ -395,8 +395,8 @@ class Primitive : public Type {

class Typedef : public Type {
public:
explicit Typedef(NodeId id, const std::string& name, Type& underlyingType)
: name_(name), underlyingType_(underlyingType), id_(id) {
explicit Typedef(NodeId id, std::string name, Type& underlyingType)
: name_(std::move(name)), underlyingType_(underlyingType), id_(id) {
}

DECLARE_ACCEPT
Expand Down Expand Up @@ -520,6 +520,8 @@ class DummyAllocator : public Type {
uint64_t align_;
};

Type& stripTypedefs(Type& type);

} // namespace type_graph

#undef DECLARE_ACCEPT
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ target_link_libraries(integration_sleepy folly_headers)

add_executable(test_type_graph
main.cpp
test_add_children.cpp
test_add_padding.cpp
test_alignment_calc.cpp
test_codegen.cpp
Expand Down
Loading