minix/minix/llvm/passes/magic/support/EDIType.cpp
David van Moolenbroek 3e457fe321 Import magic pass from llvm-apps
Change-Id: I19535b913b50f2ff24aeb80ddefc92e305c31fe8
2015-09-17 13:57:53 +00:00

521 lines
16 KiB
C++

#include <magic/support/EDIType.h>
using namespace llvm;
namespace llvm {
#define DEBUG_EDI_EQUALS 0
int debugEDIEquals = 0;
//===----------------------------------------------------------------------===//
// Constructors, destructor, and operators
//===----------------------------------------------------------------------===//
EDIType::EDIType(const MDNode *N, bool norm, bool checkOpaqueTypes) : aDIType(N) {
init(norm, checkOpaqueTypes);
}
EDIType::EDIType(bool norm, bool checkOpaqueTypes) : aDIType() {
init(norm, checkOpaqueTypes);
}
EDIType::EDIType(const DIType aDIType, bool norm, bool checkOpaqueTypes) : aDIType(aDIType) {
init(norm, checkOpaqueTypes);
}
bool EDIType::operator == (const EDIType& aEDIType) const {
const DIType oDIType = *(aEDIType.getDIType());
return (aDIType == oDIType);
}
//===----------------------------------------------------------------------===//
// Getters
//===----------------------------------------------------------------------===//
const std::string EDIType::getDescription(int skipUnions, int skipStructs, int allowMultiNames) const {
std::string string;
raw_string_ostream ostream(string);
printDescription(ostream, skipUnions, skipStructs, allowMultiNames);
ostream.flush();
return string;
}
const EDIType& EDIType::getContainedType(unsigned i, bool norm) const {
static EDIType subType;
EDIType_assert(!isBasicType() && !isVoidTy() && !isEnumTy());
bool isArrayOrVectorTy = isArrayTy() || isVectorTy();
if(isDerivedType() || isArrayOrVectorTy) {
EDIType_assert(i == 0);
if(isArrayOrVectorTy && getCurrentDimension() < getNumDimensions()-1) {
subType = *this;
subType.setCurrentDimension(getCurrentDimension() + 1);
}
else {
subType = getTypeDerivedFrom();
}
return subType;
}
DIArray aDIArray = getTypeArray();
unsigned numContainedTypes = aDIArray.getNumElements();
assert(i < numContainedTypes);
EDIType tmpType((const DIType) aDIArray.getElement(i), norm);
subType = tmpType;
return subType;
}
unsigned EDIType::getNumContainedTypes() const {
if(isBasicType() || isVoidTy() || isEnumTy()) {
return 0;
}
bool isArrayOrVectorTy = isArrayTy() || isVectorTy();
if(isDerivedType() || isArrayOrVectorTy) {
return 1;
}
DIArray aDIArray = getTypeArray();
unsigned numContainedTypes = aDIArray.getNumElements();
return numContainedTypes;
}
const DIDerivedType& EDIType::getMember(unsigned i) const {
static DIDerivedType aDIDerivedType;
EDIType_assert(isUnionOrStructTy());
DIArray aDIArray = getTypeArray();
DIDescriptor aDIDescriptor = aDIArray.getElement(i);
assert(aDIDescriptor.getTag() == dwarf::DW_TAG_member);
aDIDerivedType = (DIDerivedType) aDIDescriptor;
return aDIDerivedType;
}
bool EDIType::isUnionOrStructTy(bool isStruct, bool isUnion) const {
if(isOpaqueTy()) {
return false;
}
if((isStruct && getTag() == dwarf::DW_TAG_structure_type) ||
(isUnion && getTag() == dwarf::DW_TAG_union_type)) {
EDIType_assert(isCompositeType());
return true;
}
return false;
}
bool EDIType::hasInnerPointers() const {
if(isOpaqueTy() || isFunctionTy()) {
return false;
}
if(isPointerTy()) {
return true;
}
unsigned numContainedTypes = getNumContainedTypes();
if(numContainedTypes == 0) {
return false;
}
else if(isArrayTy() || isVectorTy()) {
const EDIType subType = getContainedType(0);
return subType.hasInnerPointers();
}
else {
assert(isUnionOrStructTy());
for(unsigned i=0;i<numContainedTypes;i++) {
const EDIType subType = getContainedType(i);
if(subType.hasInnerPointers()) {
return true;
}
}
}
return false;
}
DIArray EDIType::getTypeArray() const {
static std::set<std::string> nonOpaqueEmptyTypes;
static std::set<std::string>::iterator nonOpaqueEmptyTypesIt;
EDIType_assert(isCompositeType());
DIArray aDIArray = ((const DICompositeType)aDIType).getTypeArray();
if(aDIArray.getNumElements() == 0 && checkOpaqueTypes && myNames.size() > 0) {
const EDIType *aType = NULL;
std::string name;
for(int i=myNames.size()-1;i>=0;i--) {
name = myNames[i];
aType = getStructEDITypeByName(name);
if(aType) {
break;
}
}
if(aType) {
aDIArray = ((const DICompositeType *)aType->getDIType())->getTypeArray();
nonOpaqueEmptyTypesIt = nonOpaqueEmptyTypes.find(name);
if(nonOpaqueEmptyTypesIt == nonOpaqueEmptyTypes.end()) {
EDITypeLog("Found a non-opaque composite type with 0 members! Name is: " << name);
nonOpaqueEmptyTypes.insert(name);
}
}
}
return aDIArray;
}
const EDIType* EDIType::getTopStructType(unsigned index) const {
static unsigned level = 0;
static unsigned structsLeft;
static EDIType targetType;
if(level == 0) {
structsLeft = index;
}
if(isUnionOrStructTy() || isOpaqueTy()) {
if(structsLeft == 0) {
targetType = *this;
return &targetType;
}
else {
structsLeft--;
return NULL;
}
}
unsigned numContainedTypes = getNumContainedTypes();
for(unsigned i=0;i<numContainedTypes;i++) {
const EDIType containedType(getContainedType(i));
level++;
const EDIType *topStructType = containedType.getTopStructType(index);
level--;
if(topStructType != NULL) {
return topStructType;
}
}
return NULL;
}
//===----------------------------------------------------------------------===//
// Other public methods
//===----------------------------------------------------------------------===//
void EDIType::print(raw_ostream &OS) const {
OS << getDescription();
}
void EDIType::printDescription(raw_ostream &OS, int skipUnions, int skipStructs, int allowMultiNames) const {
static std::vector<const EDIType*> nestedTypes;
int printMultiNames = allowMultiNames && myNames.size() > 1;
if(allowMultiNames && !printMultiNames && isPointerTy() && myName.compare("")) {
printMultiNames = 1;
}
if(isOpaqueTy()) {
OS << "opaque";
return;
}
unsigned numContainedTypes = getNumContainedTypes();
if(numContainedTypes == 0) {
OS << (printMultiNames ? getNamesString() : getName());
return;
}
if(isPointerTy() && getContainedType(0).isUnionOrStructTy()) {
bool isNestedType = false;
unsigned j;
for(j=0;j<nestedTypes.size();j++) {
if(nestedTypes[j]->equals(this)) {
isNestedType = true;
break;
}
}
if(isNestedType) {
OS << "\\" << nestedTypes.size() - j;
return;
}
}
nestedTypes.push_back(this);
if(isPointerTy()) {
const EDIType subType = getContainedType(0);
subType.printDescription(OS, skipUnions, skipStructs, allowMultiNames);
OS << "*";
if(printMultiNames) {
OS << "|" << getNamesString();
}
}
else if(isArrayTy() || isVectorTy()) {
const EDIType subType = getContainedType(0);
unsigned numElements = getNumElements();
char startSep = isArrayTy() ? '[' : '<';
char endSep = isArrayTy() ? ']' : '>';
OS << startSep;
if(numElements) {
OS << numElements << " x ";
}
subType.printDescription(OS, skipUnions, skipStructs, allowMultiNames);
OS << endSep;
}
else if(isUnionOrStructTy()) {
if(skipUnions && isUnionTy()) {
OS << "(U) $" << (printMultiNames ? getNamesString() : (myName.compare("") ? myName : "ANONYMOUS"));
nestedTypes.pop_back();
return;
}
if(skipStructs && isStructTy()) {
OS << "$" << (printMultiNames ? getNamesString() : (myName.compare("") ? myName : "ANONYMOUS"));
nestedTypes.pop_back();
return;
}
unsigned numContainedTypes = getNumContainedTypes();
OS << "{ ";
if(isUnionTy()) {
OS << "(U) ";
}
OS << "$" << (printMultiNames ? getNamesString() : (myName.compare("") ? myName : "ANONYMOUS")) << " ";
for(unsigned i=0;i<numContainedTypes;i++) {
if(i > 0) {
OS << ", ";
}
EDIType subType = getContainedType(i);
subType.printDescription(OS, skipUnions, skipStructs, allowMultiNames);
}
OS << " }";
}
else if(isFunctionTy()) {
unsigned numContainedTypes = getNumContainedTypes();
assert(numContainedTypes > 0);
EDIType subType = getContainedType(0);
subType.printDescription(OS, skipUnions, skipStructs, allowMultiNames);
numContainedTypes--;
OS << " (";
for(unsigned i=0;i<numContainedTypes;i++) {
if(i > 0) {
OS << ", ";
}
subType = getContainedType(i+1);
subType.printDescription(OS, skipUnions, skipStructs, allowMultiNames);
}
OS << ")";
}
else {
OS << "???";
}
nestedTypes.pop_back();
}
bool EDIType::equals(const EDIType *other) const {
static std::set<std::pair<MDNode*, MDNode*> > compatibleMDNodes;
static std::set<std::pair<MDNode*, MDNode*> >::iterator compatibleMDNodesIt;
static int max_recursive_steps = -1;
#if DEBUG_EDI_EQUALS
if(debugEDIEquals>1) EDITypeErr("COMPARING :" << getTag() << ":" << getName() << " VS " << other->getTag() << ":" << other->getName());
#endif
if(isOpaqueTy() || other->isOpaqueTy()) {
#if DEBUG_EDI_EQUALS
if(debugEDIEquals) EDITypeErr("----> ???1");
#endif
return isOpaqueTy() && other->isOpaqueTy();
}
if(getTag() != other->getTag()) {
#if DEBUG_EDI_EQUALS
if(debugEDIEquals) EDITypeErr("----> false1");
#endif
return false;
}
unsigned numContainedTypes = getNumContainedTypes();
unsigned numOtherContainedTypes = other->getNumContainedTypes();
if(numContainedTypes != numOtherContainedTypes) {
#if DEBUG_EDI_EQUALS
if(debugEDIEquals) EDITypeErr("----> false2");
#endif
return false;
}
if(getNumElements() != other->getNumElements()) {
#if DEBUG_EDI_EQUALS
if(debugEDIEquals) EDITypeErr("----> false3");
#endif
return false;
}
if(myName.compare(other->getName())) {
#if DEBUG_EDI_EQUALS
if(debugEDIEquals) EDITypeErr("----> false4");
#endif
return false;
}
if((myNames.size() > 0 || other->getNames().size() > 0) && getNamesString().compare(other->getNamesString())) {
#if DEBUG_EDI_EQUALS
if(debugEDIEquals) EDITypeErr("----> false5");
#endif
return false;
}
if(numContainedTypes == 0) {
#if DEBUG_EDI_EQUALS
if(debugEDIEquals) EDITypeErr("----> true1");
#endif
return true;
}
MDNode *aNode = *(&aDIType);
MDNode *otherNode = *(other->getDIType());
if(aNode == otherNode) {
#if DEBUG_EDI_EQUALS
if(debugEDIEquals) EDITypeErr("----> true2");
#endif
return true;
}
int isUnionOrStruct = isUnionOrStructTy();
int isNonAnonUnionOrStruct = isUnionOrStruct && myName.size() > 0;
int saved_max_recursive_steps = max_recursive_steps;
if(max_recursive_steps == -1 && isNonAnonUnionOrStruct) {
//A simple way to break recursion for recursive non-anonymous structs/unions.
max_recursive_steps = 10;
}
else if(max_recursive_steps == 0) {
#if DEBUG_EDI_EQUALS
if(debugEDIEquals) EDITypeErr("----> true4");
#endif
return true;
}
else {
max_recursive_steps--;
}
for(unsigned i=0;i<numContainedTypes;i++) {
const EDIType &subEDIType = getContainedType(i);
const EDIType &subOtherEDIType = other->getContainedType(i);
if(!subEDIType.equals(&subOtherEDIType)) {
max_recursive_steps = saved_max_recursive_steps;
return false;
}
}
max_recursive_steps = saved_max_recursive_steps;
return true;
}
//===----------------------------------------------------------------------===//
// Public static methods
//===----------------------------------------------------------------------===//
std::string EDIType::lookupTypedefName(std::string &typedefName) {
static std::string noName;
for (DebugInfoFinder::iterator I = DIFinder.type_begin(),
E = DIFinder.type_end(); I != E; ++I) {
DIType aDIType(*I);
if(aDIType.getTag() == dwarf::DW_TAG_typedef && aDIType.getName().compare(typedefName)) {
while(aDIType.getTag() == dwarf::DW_TAG_typedef) {
aDIType = PassUtil::getDITypeDerivedFrom((const DIDerivedType)aDIType);
}
if(aDIType.getName().compare("")) {
return aDIType.getName();
}
}
}
return noName;
}
std::string EDIType::lookupUnionMemberName(TYPECONST Type* type) {
std::string string;
std::string error;
if(!type->isStructTy() || type->getNumContainedTypes() != 1) {
return "";
}
raw_string_ostream ostream(string);
writeTypeSymbolic(ostream, type->getContainedType(0), EDIType::module);
ostream.flush();
Regex unionRegex("%(union|struct)\\.([^ ]+)", 0);
assert(unionRegex.isValid(error));
SmallVector<StringRef, 8> unionMatches;
if(unionRegex.match(string, &unionMatches)) {
return unionMatches[2];
}
return "";
}
const EDIType* EDIType::getStructEDITypeByName(std::string &typeName) {
static EDIType aEDIType;
assert(module);
for (DebugInfoFinder::iterator I = DIFinder.type_begin(),
E = DIFinder.type_end(); I != E; ++I) {
const DIType aDIType(*I);
//skip zero-element stuct types, necessary to avoid infinite recursion during opaque type lookup
//xxx opaque type lookup should not be necessary but is there a bug in the frontend that leaves certain concrete types unnecessarily opaque?
const EDIType tmpEDIType(aDIType, NORMALIZE, DO_NOT_CHECK_OPAQUE_TYPES);
aEDIType = tmpEDIType;
if(typeName.compare(aEDIType.getName())) {
continue;
}
if(aEDIType.isUnionOrStructTy()) {
return &aEDIType;
}
}
return NULL;
}
void EDIType::setModule(Module *M) {
assert(module == NULL);
module = M;
DIFinder.processModule(*module);
}
//===----------------------------------------------------------------------===//
// Private methods
//===----------------------------------------------------------------------===//
void EDIType::init(bool norm, bool checkOpaqueTypes) {
EDIType_assert(isType());
currentDimension = 0;
this->checkOpaqueTypes = checkOpaqueTypes;
myName = "";
if(norm) {
normalize();
}
if(myNames.size() == 0) {
//nobody assigned names yet, do it here
myName = isVoidTy() ? voidName : aDIType.getName();
if(myName.compare("")) {
myNames.push_back(myName);
}
}
}
void EDIType::normalize() {
if(getTag() == dwarf::DW_TAG_typedef) {
normalizeTypedef();
}
if(isBasicType() || isVoidTy() || isEnumTy() || isOpaqueTy()) {
return;
}
if(isDerivedType()) {
if(isPointerTy() || isUnionOrStructTy()) {
return;
}
aDIType = PassUtil::getDITypeDerivedFrom((const DIDerivedType)aDIType);
normalize();
return;
}
EDIType_assert(isCompositeType());
if(isAggregateType() || isVectorTy() || isFunctionTy()) {
return;
}
EDIType_assert(getNumContainedTypes() == 1);
aDIType = *(getContainedType(0, DO_NOT_NORMALIZE).getDIType());
normalize();
}
void EDIType::normalizeTypedef() {
myNames.clear();
while(aDIType.getTag() == dwarf::DW_TAG_typedef) {
if(aDIType.getName().compare("")) {
myNames.push_back(aDIType.getName());
}
aDIType = PassUtil::getDITypeDerivedFrom((const DIDerivedType)aDIType);
}
myName = isVoidTy() ? voidName : aDIType.getName();
if(!myName.compare("")) {
//anonymous typedefed type, use the deepest typedef name
assert(!isBasicType());
assert(myNames.size() > 0);
myName = myNames[myNames.size()-1];
}
else {
myNames.push_back(myName);
}
}
StringRef EDIType::voidName("void");
Module *EDIType::module = NULL;
DebugInfoFinder EDIType::DIFinder;
}