#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Support/raw_ostream.h"
#define DEFAULTSUBSTR "<default>"
using
namespace
llvm;
namespace
{
static
cl::opt<
int
> passmode
(
"passmode"
,
cl::desc(
"absolute offset or not"
),
cl::value_desc(
"int"
),
cl::init(0)
);
static
cl::opt<std::string> substr
(
"substr"
,
cl::desc(
"part of struct name"
),
cl::value_desc(
"std::string"
),
cl::init(DEFAULTSUBSTR)
);
struct
DumpClass : PassInfoMixin<DumpClass>
{
std::string getTypeName ( Type *type,
const
DataLayout &data )
{
if
( type->isIntegerTy() )
{
IntegerType *i = cast<IntegerType>( type );
return
"uint"
+ std::to_string( i->getBitWidth() ) +
"_t"
;
}
else
if
( type->isPointerTy() )
{
PointerType *ptr = cast<PointerType>( type );
return
getTypeName( ptr->getPointerElementType(), data ) +
"*"
;
}
else
if
( type->isArrayTy() )
{
ArrayType *arr = cast<ArrayType>( type );
return
getTypeName( arr->getArrayElementType(), data ) +
"["
+ std::to_string( arr->getArrayNumElements() ) +
"]"
;
}
else
if
( type->isFloatTy() )
{
return
"float"
;
}
else
if
( type->isStructTy() )
{
StructType *stc = cast<StructType>( type );
return
std::string( stc->getStructName() );
}
else
{
return
"unknown_"
+ std::to_string( data.getTypeAllocSizeInBits( type ) );
}
}
void
dumpType (
int
depth, Type *type,
const
std::string &suffix,
const
DataLayout *data, unsigned base,
int
mode )
{
std::string blank( depth * 4,
' '
);
if
( type->isStructTy() )
{
StructType *stc = cast<StructType>( type );
const
StructLayout *sl = data->getStructLayout( stc );
errs() << blank + stc->getStructName() +
"\n"
+ blank +
"{\n"
;
for
(
size_t
i = 0; i < stc->getStructNumElements(); i++ )
{
Type *subType = stc->getStructElementType( i );
unsigned offset = sl->getElementOffset( i );
unsigned size = data->getTypeAllocSize( subType );
if
( mode > 0 )
{
offset += base;
dumpType( depth+1, subType, std::to_string(offset)+
"_"
+std::to_string(size), data, offset, mode );
}
else
{
dumpType( depth+1, subType, std::to_string(offset)+
"_"
+std::to_string(size), data, 0, mode );
}
}
errs() << blank +
"} field_"
+ suffix +
";\n"
;
}
else
{
errs() << blank + getTypeName( type, *data ) +
" field_"
+ suffix +
";\n"
;
}
}
void
visitor ( Function &F )
{
if
( F.getName() !=
"main"
)
{
return
;
}
std::set<StructType*> types;
const
DataLayout &data = F.getParent()->getDataLayout();
for
(
auto
&B : F )
{
for
(
auto
&I : B )
{
if
(
auto
*A = dyn_cast<AllocaInst>( &I ) )
{
Type *type = A->getAllocatedType();
if
( type->isStructTy() )
{
StructType *stc = cast<StructType>( type );
if
( stc->isOpaque() )
{
continue
;
}
std::string struct_name
= std::string( stc->getStructName() );
if
( substr != DEFAULTSUBSTR && struct_name.find( substr ) == std::string::npos )
{
continue
;
}
types.insert( stc );
}
}
}
}
int
index = 0;
for
( StructType *type : types )
{
dumpType( 0, type, std::to_string( index++ ), &data, 0, passmode );
}
}
PreservedAnalyses run ( Function &F, FunctionAnalysisManager &FAM )
{
visitor( F );
return
PreservedAnalyses::all();
}
};
}
PassPluginLibraryInfo getDumpClassPluginInfo ()
{
const
auto
callback = []( PassBuilder &PB )
{
PB.registerPipelineParsingCallback
(
[](
StringRef Name,
FunctionPassManager &FPM,
ArrayRef<PassBuilder::PipelineElement>
)
{
if
( Name ==
"DumpClass"
)
{
FPM.addPass( DumpClass() );
return
true
;
}
return
false
;
}
);
PB.registerPipelineStartEPCallback
(
[&]( ModulePassManager &MPM,
auto
)
{
FunctionPassManager FPM;
FPM.addPass( DumpClass() );
MPM.addPass( createModuleToFunctionPassAdaptor( std::move( FPM ) ) );
return
true
;
}
);
};
return
{ LLVM_PLUGIN_API_VERSION,
"DumpClass"
, LLVM_VERSION_STRING, callback };
}
extern
"C"
LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo llvmGetPassPluginInfo ()
{
return
getDumpClassPluginInfo();
}