Skip to content

Commit

Permalink
named types
Browse files Browse the repository at this point in the history
  • Loading branch information
2over12 committed Nov 30, 2023
1 parent ebd47cc commit 4b56e77
Show file tree
Hide file tree
Showing 10 changed files with 155 additions and 34 deletions.
7 changes: 7 additions & 0 deletions include/anvill/Providers.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#pragma once

#include <llvm/IR/DataLayout.h>
#include <llvm/IR/DerivedTypes.h>

#include <cstdint>
#include <functional>
Expand Down Expand Up @@ -71,6 +72,8 @@ class TypeProvider {

virtual const ::anvill::TypeDictionary &Dictionary(void) const = 0;

virtual std::vector<llvm::StructType *> NamedTypes(void) const = 0;

virtual ~TypeProvider() = default;
};

Expand Down Expand Up @@ -149,6 +152,8 @@ class ProxyTypeProvider : public TypeProvider {
std::optional<uint64_t>)>
typed_reg_cb) const override;

std::vector<llvm::StructType *> NamedTypes(void) const override;

const ::anvill::TypeDictionary &Dictionary(void) const override;
};

Expand Down Expand Up @@ -199,6 +204,8 @@ class SpecificationTypeProvider : public BaseTypeProvider {
TryGetVariableType(uint64_t address,
llvm::Type *hinted_value_type = nullptr) const override;

std::vector<llvm::StructType *> NamedTypes(void) const override;

private:
SpecificationTypeProvider(void) = delete;
};
Expand Down
19 changes: 18 additions & 1 deletion include/anvill/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,21 @@ struct UnknownType {
bool operator==(const UnknownType &) const = default;
};


class TypeName {
public:
std::string name;

bool operator==(const TypeName &) const = default;

explicit TypeName(std::string name) : name(name) {}
};

using TypeSpec =
std::variant<BaseType, std::shared_ptr<PointerType>,
std::shared_ptr<VectorType>, std::shared_ptr<ArrayType>,
std::shared_ptr<StructType>, std::shared_ptr<FunctionType>,
UnknownType>;
UnknownType, TypeName>;

bool operator==(std::shared_ptr<PointerType>, std::shared_ptr<PointerType>);
bool operator==(std::shared_ptr<VectorType>, std::shared_ptr<VectorType>);
Expand Down Expand Up @@ -285,6 +295,13 @@ class TypeTranslator {


namespace std {
template <>
struct hash<anvill::TypeName> {
size_t operator()(const anvill::TypeName &unk) const {
return std::hash<std::string>()(unk.name);
}
};

template <>
struct hash<anvill::UnknownType> {
size_t operator()(const anvill::UnknownType &unk) const {
Expand Down
3 changes: 2 additions & 1 deletion lib/Declarations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,8 @@ CallableDecl::DecodeFromPB(const remill::Arch *arch, const std::string &pb) {
const TypeDictionary type_dictionary(*(arch->context));
const TypeTranslator type_translator(type_dictionary, arch);
std::unordered_map<std::int64_t, TypeSpec> type_map;
ProtobufTranslator translator(type_translator, arch, type_map);
std::unordered_map<std::int64_t, std::string> type_names;
ProtobufTranslator translator(type_translator, arch, type_map, type_names);

auto default_callable_decl_res =
translator.DecodeDefaultCallableDecl(function);
Expand Down
10 changes: 10 additions & 0 deletions lib/Lifters/EntityLifter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
#include <glog/logging.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/GlobalAlias.h>
#include <llvm/IR/GlobalVariable.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/TypeFinder.h>
#include <llvm/Transforms/Utils/ModuleUtils.h>
#include <remill/Arch/Arch.h>
#include <remill/BC/Util.h>
Expand All @@ -35,6 +37,14 @@ EntityLifterImpl::EntityLifterImpl(const LifterOptions &options_)
data_lifter(options) {
CHECK_EQ(options.arch->context, &(options.module->getContext()));
options.arch->PrepareModule(options.module);

// Lift named types
for (auto sty : this->type_provider->NamedTypes()) {
auto gv = new llvm::GlobalVariable(*options.module, sty, false,
llvm::GlobalValue::ExternalLinkage,
nullptr, sty->getName() + "_var_repr");
llvm::appendToUsed(*options.module, gv);
}
}

// Tells the entity lifter that `entity` is the lifted function/data at
Expand Down
62 changes: 46 additions & 16 deletions lib/Protobuf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include <anvill/Type.h>
#include <glog/logging.h>
#include <llvm/IR/DataLayout.h>
#include <llvm/IR/DerivedTypes.h>
#include <llvm/Support/Casting.h>
#include <remill/Arch/Arch.h>
#include <remill/Arch/Name.h>
#include <remill/BC/Error.h>
Expand Down Expand Up @@ -261,14 +263,16 @@ Result<std::monostate, std::string> ProtobufTranslator::ParseIntoCallableDecl(

ProtobufTranslator::ProtobufTranslator(
const anvill::TypeTranslator &type_translator_, const remill::Arch *arch_,
std::unordered_map<std::int64_t, TypeSpec> &type_map)
std::unordered_map<std::int64_t, TypeSpec> &type_map,
std::unordered_map<std::int64_t, std::string> &type_names)
: arch(arch_),
type_translator(type_translator_),
context(*(arch->context)),
void_type(llvm::Type::getVoidTy(context)),
dict_void_type(remill::RecontextualizeType(
type_translator.Dictionary().u.named.void_, context)),
type_map(type_map) {}
type_map(type_map),
type_names(type_names) {}


anvill::Result<LowLoc, std::string>
Expand Down Expand Up @@ -462,8 +466,9 @@ ProtobufTranslator::DecodeType(const ::specification::TypeSpec &obj) const {
}
}
if (obj.has_alias()) {
if (type_map.count(obj.alias())) {
return type_map.at(obj.alias());
if (this->type_names.count(obj.alias())) {
TypeSpec res = TypeName(type_names.at(obj.alias()));
return res;
} else {
LOG(ERROR) << "Unknown alias id " << obj.alias();
return {BaseType::Void};
Expand Down Expand Up @@ -802,9 +807,15 @@ Result<VariableDecl, std::string> ProtobufTranslator::DecodeGlobalVar(

anvill::Result<TypeSpec, std::string> ProtobufTranslator::DecodeType(
const ::specification::TypeSpec &obj,
const std::unordered_map<std::int64_t, ::specification::TypeSpec> &map) {
const std::unordered_map<std::int64_t, ::specification::TypeSpec> &map,
const std::unordered_map<std::int64_t, std::string> &named_types) {
if (obj.has_alias()) {
auto alias = obj.alias();
if (named_types.contains(alias)) {
TypeSpec tname = TypeName(named_types.at(alias));
return tname;
}

if (type_map.count(alias)) {
return type_map[alias];
}
Expand All @@ -816,7 +827,7 @@ anvill::Result<TypeSpec, std::string> ProtobufTranslator::DecodeType(
return {BaseType::Void};
}

auto res = DecodeType(map.at(alias), map);
auto res = DecodeType(map.at(alias), map, named_types);
if (!res.Succeeded()) {
return res.TakeError();
}
Expand All @@ -827,7 +838,7 @@ anvill::Result<TypeSpec, std::string> ProtobufTranslator::DecodeType(
auto pointer = obj.pointer();
TypeSpec pointee = BaseType::Void;
if (pointer.has_pointee()) {
auto maybe_pointee = DecodeType(pointer.pointee(), map);
auto maybe_pointee = DecodeType(pointer.pointee(), map, named_types);
if (!maybe_pointee.Succeeded()) {
return maybe_pointee.Error();
}
Expand All @@ -840,7 +851,7 @@ anvill::Result<TypeSpec, std::string> ProtobufTranslator::DecodeType(
if (!vector.has_base()) {
return {"Vector type without base type"};
}
auto maybe_base = DecodeType(vector.base(), map);
auto maybe_base = DecodeType(vector.base(), map, named_types);
if (!maybe_base.Succeeded()) {
return maybe_base.Error();
}
Expand All @@ -851,7 +862,7 @@ anvill::Result<TypeSpec, std::string> ProtobufTranslator::DecodeType(
if (!array.has_base()) {
return {"Array type without base type"};
}
auto maybe_base = DecodeType(array.base(), map);
auto maybe_base = DecodeType(array.base(), map, named_types);
if (!maybe_base.Succeeded()) {
return maybe_base.Error();
}
Expand All @@ -860,7 +871,7 @@ anvill::Result<TypeSpec, std::string> ProtobufTranslator::DecodeType(
if (obj.has_struct_()) {
auto res = std::make_shared<StructType>();
for (auto elem : obj.struct_().members()) {
auto maybe_type = DecodeType(elem, map);
auto maybe_type = DecodeType(elem, map, named_types);
if (!maybe_type.Succeeded()) {
return maybe_type.Error();
}
Expand All @@ -874,14 +885,14 @@ anvill::Result<TypeSpec, std::string> ProtobufTranslator::DecodeType(
return {"Function without return type"};
}
auto res = std::make_shared<FunctionType>();
auto maybe_ret = DecodeType(func.return_type(), map);
auto maybe_ret = DecodeType(func.return_type(), map, named_types);
if (!maybe_ret.Succeeded()) {
return maybe_ret.Error();
}
res->return_type = std::move(maybe_ret.Value());
res->is_variadic = func.is_variadic();
for (auto arg : func.arguments()) {
auto maybe_argtype = DecodeType(arg, map);
auto maybe_argtype = DecodeType(arg, map, named_types);
if (!maybe_argtype.Succeeded()) {
return maybe_argtype.Error();
}
Expand All @@ -893,17 +904,36 @@ anvill::Result<TypeSpec, std::string> ProtobufTranslator::DecodeType(
}

Result<std::monostate, std::string> ProtobufTranslator::DecodeTypeMap(
const ::google::protobuf::Map<std::int64_t, ::specification::TypeSpec>
&map) {
const ::google::protobuf::Map<std::int64_t, ::specification::TypeSpec> &map,
const ::google::protobuf::Map<std::int64_t, std::string> &names) {
for (auto &[k, v] : map) {
if (type_map.count(k)) {
continue;
}
auto res = DecodeType(v, {map.begin(), map.end()});
auto res =
DecodeType(v, {map.begin(), map.end()}, {names.begin(), names.end()});

if (!res.Succeeded()) {
return res.Error();
}
type_map[k] = res.Value();


if (names.contains(k)) {
auto ty = this->type_translator.DecodeFromSpec(res.Value());
if (!ty.Succeeded()) {
return ty.Error().message;
}

if (auto *sty = llvm::dyn_cast<llvm::StructType>(ty.Value())) {


std::string name = names.at(k);
llvm::StructType::create(this->context, sty->elements(), name);
}
type_names[k] = names.at(k);
} else {
type_map[k] = res.Value();
}
}
return std::monostate{};
}
Expand Down
23 changes: 14 additions & 9 deletions lib/Protobuf.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,15 @@ class ProtobufTranslator {
llvm::Type *const dict_void_type;

std::unordered_map<std::int64_t, TypeSpec> &type_map;
std::unordered_map<std::int64_t, std::string> &type_names;

anvill::Result<TypeSpec, std::string>
DecodeType(const ::specification::TypeSpec &obj) const;

anvill::Result<TypeSpec, std::string> DecodeType(
const ::specification::TypeSpec &obj,
const std::unordered_map<std::int64_t, ::specification::TypeSpec> &map);
const std::unordered_map<std::int64_t, ::specification::TypeSpec> &map,
const std::unordered_map<std::int64_t, std::string> &named_types);


// Parse the location of a value. This applies to both parameters and
Expand Down Expand Up @@ -90,22 +92,24 @@ class ProtobufTranslator {
FunctionDecl &decl) const;

void AddLiveValuesToBB(
std::unordered_map<Uid, std::vector<ParameterDecl>> &map,
Uid bb_uid,
std::unordered_map<Uid, std::vector<ParameterDecl>> &map, Uid bb_uid,
const ::google::protobuf::RepeatedPtrField<::specification::Parameter>
&values) const;


public:
explicit ProtobufTranslator(
const anvill::TypeTranslator &type_translator_, const remill::Arch *arch_,
std::unordered_map<std::int64_t, TypeSpec> &type_map);
std::unordered_map<std::int64_t, TypeSpec> &type_map,
std::unordered_map<std::int64_t, std::string> &type_names);

inline explicit ProtobufTranslator(
const anvill::TypeTranslator &type_translator_,
const std::unique_ptr<const remill::Arch> &arch_,
std::unordered_map<std::int64_t, TypeSpec> &type_map)
: ProtobufTranslator(type_translator_, arch_.get(), type_map) {}
std::unordered_map<std::int64_t, TypeSpec> &type_map,
std::unordered_map<std::int64_t, std::string> &type_names)
: ProtobufTranslator(type_translator_, arch_.get(), type_map,
type_names) {}

// Parse a parameter from the Protobuf spec. Parameters should have names,
// as that makes the bitcode slightly easier to read, but names are
Expand Down Expand Up @@ -133,9 +137,10 @@ class ProtobufTranslator {
Result<CallableDecl, std::string>
DecodeDefaultCallableDecl(const ::specification::Function &obj) const;

Result<std::monostate, std::string>
DecodeTypeMap(const ::google::protobuf::Map<std::int64_t,
::specification::TypeSpec> &map);
Result<std::monostate, std::string> DecodeTypeMap(
const ::google::protobuf::Map<std::int64_t, ::specification::TypeSpec>
&map,
const ::google::protobuf::Map<std::int64_t, std::string> &names);
};

} // namespace anvill
20 changes: 20 additions & 0 deletions lib/Providers/TypeProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <algorithm>
#include <optional>
#include <type_traits>
#include <vector>

#include "Specification.h"

Expand Down Expand Up @@ -97,6 +98,20 @@ SpecificationTypeProvider::TryGetFunctionType(uint64_t address) const {
}
}

std::vector<llvm::StructType *>
SpecificationTypeProvider::NamedTypes(void) const {
std::vector<llvm::StructType *> stys;

for (auto nms : this->impl->named_types) {
auto sty = llvm::StructType::getTypeByName(this->context, nms);
if (sty) {
stys.push_back(sty);
}
}

return stys;
}

std::optional<anvill::VariableDecl>
SpecificationTypeProvider::TryGetVariableType(uint64_t address,
llvm::Type *) const {
Expand Down Expand Up @@ -179,6 +194,11 @@ void ProxyTypeProvider::QueryRegisterStateAtInstruction(
typed_reg_cb);
}

std::vector<llvm::StructType *> ProxyTypeProvider::NamedTypes(void) const {
return this->deleg.NamedTypes();
}


const ::anvill::TypeDictionary &ProxyTypeProvider::Dictionary(void) const {
return this->deleg.Dictionary();
}
Expand Down
Loading

0 comments on commit 4b56e77

Please sign in to comment.