blob: 77835881f91e1d1dae31fa6a4a6aa629904e0149 [file] [log] [blame]
/*
* TreeItems.cpp
*/
#include "llvm/LLVMContext.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Module.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/TypeSymbolTable.h"
#include "llbrowse/Formatting.h"
#include "llbrowse/TreeView.h"
#include "llbrowse/DetailsView.h"
#include "llbrowse/Resources.h"
#include "wx/sstream.h"
using namespace llvm;
namespace {
wxString GetLinkageName(GlobalValue::LinkageTypes linkage) {
switch (linkage) {
case GlobalValue::ExternalLinkage:
return _("ExternalLinkage");
case GlobalValue::AvailableExternallyLinkage:
return _("AvailableExternallyLinkage");
case GlobalValue::LinkOnceAnyLinkage:
return _("LinkOnceAnyLinkage");
case GlobalValue::LinkOnceODRLinkage:
return _("LinkOnceODRLinkage");
case GlobalValue::WeakAnyLinkage:
return _("WeakAnyLinkage");
case GlobalValue::WeakODRLinkage:
return _("WeakODRLinkage");
case GlobalValue::AppendingLinkage:
return _("AppendingLinkage");
case GlobalValue::InternalLinkage:
return _("InternalLinkage");
case GlobalValue::PrivateLinkage:
return _("PrivateLinkage");
case GlobalValue::LinkerPrivateLinkage:
return _("LinkerPrivateLinkage");
case GlobalValue::LinkerPrivateWeakLinkage:
return _("LinkerPrivateWeakLinkage");
case GlobalValue::LinkerPrivateWeakDefAutoLinkage:
return _("LinkerPrivateWeakDefAutoLinkage");
case GlobalValue::DLLImportLinkage:
return _("DLLImportLinkage");
case GlobalValue::DLLExportLinkage:
return _("DLLExportLinkage");
case GlobalValue::ExternalWeakLinkage:
return _("ExternalWeakLinkage");
case GlobalValue::CommonLinkage:
return _("CommonLinkage");
default:
assert(false && "Invalid linkage type!");
return wxString();
}
}
wxString GetDITagName(unsigned tag) {
return wxString::From8BitData(dwarf::TagString(tag));
}
}
//===----------------------------------------------------------------------===//
// TreeItemBase Implementation
//===----------------------------------------------------------------------===//
IMPLEMENT_DYNAMIC_CLASS(TreeView, wxTreeCtrl)
void TreeView::SetModule(const Module* module, const wxString& rootName) {
DeleteAllItems();
rootItem_ = new ModuleItem(module);
wxTreeItemId rootId = AddRoot(rootName, 0, -1, rootItem_);
rootItem_->CreateChildren(this, rootId);
// Root item is initially expanded
Expand(rootId);
}
//===----------------------------------------------------------------------===//
// TreeItemBase Implementation
//===----------------------------------------------------------------------===//
wxTreeItemId TreeItemBase::CreateChild(
wxTreeCtrl* tree,
const wxTreeItemId & parent,
TreeItemBase* itemData)
{
wxTreeItemId id = tree->AppendItem(
parent, itemData->GetCaption(), itemData->GetIcon(), -1, itemData);
if (itemData->CanCreateChildren()) {
tree->SetItemHasChildren(id, true);
}
return id;
}
//===----------------------------------------------------------------------===//
// ModuleItem Implementation
//===----------------------------------------------------------------------===//
int ModuleItem::GetIcon() const {
return Resources::ICON_MODULE;
}
void ModuleItem::CreateChildren(wxTreeCtrl* tree, const wxTreeItemId & id) {
CreateChild(tree, id, new TypeListItem(module_));
CreateChild(tree, id, new FunctionListItem(module_));
CreateChild(tree, id, new VariableListItem(module_));
CreateChild(tree, id, new AliasListItem(module_));
CreateChild(tree, id, new NamedMetaListItem(module_));
CreateChild(tree, id, new DebugSymbolsRootItem(module_));
}
void ModuleItem::ShowDetails(DetailsView* detailsView) {
if (!module_->getModuleIdentifier().empty()) {
detailsView->Add(_("Module ID"), module_->getModuleIdentifier());
}
if (!module_->getDataLayout().empty()) {
detailsView->Add(_("Data Layout"), module_->getDataLayout());
}
if (!module_->getTargetTriple().empty()) {
detailsView->Add(_("Target Triple"), module_->getTargetTriple());
}
// For some reason this causes the app to crash in the wxWidgets translation
// string lookup code, but I can't find anything wrong with it.
switch (module_->getEndianness()) {
case Module::AnyEndianness:
detailsView->Add(_("Byte Order"), _("Any"));
break;
case Module::LittleEndian:
detailsView->Add(_("Byte Order"), _("Little Endian"));
break;
case Module::BigEndian:
detailsView->Add(_("Byte Order"), _("Big Endian"));
break;
}
/// An enumeration for describing the size of a pointer on the target machine.
// enum PointerSize { AnyPointerSize, Pointer32, Pointer64 };
// PointerSize getPointerSize() const;
}
//===----------------------------------------------------------------------===//
// ListItem Implementation
//===----------------------------------------------------------------------===//
int ListItem::GetIcon() const {
return Resources::ICON_FOLDER;
}
//===----------------------------------------------------------------------===//
// TypeListItem Implementation
//===----------------------------------------------------------------------===//
void TypeListItem::CreateChildren(
wxTreeCtrl* tree, const wxTreeItemId & id) {
const TypeSymbolTable & types = module_->getTypeSymbolTable();
for (TypeSymbolTable::const_iterator it = types.begin(), itEnd = types.end();
it != itEnd; ++it) {
CreateChild(tree, id,
new TypeItem(module_, it->second, toWxStr(it->first)));
}
tree->SortChildren(id);
}
bool TypeListItem::CanCreateChildren() const {
return !module_->getTypeSymbolTable().empty();
}
//===----------------------------------------------------------------------===//
// FunctionListItem Implementation
//===----------------------------------------------------------------------===//
void FunctionListItem::CreateChildren(
wxTreeCtrl* tree, const wxTreeItemId & id) {
const Module::FunctionListType & funcs = module_->getFunctionList();
for (Module::FunctionListType::const_iterator it = funcs.begin(),
itEnd = funcs.end();
it != itEnd; ++it) {
CreateChild(tree, id, new FunctionItem(module_, it));
}
tree->SortChildren(id);
}
bool FunctionListItem::CanCreateChildren() const {
return !module_->getFunctionList().empty();
}
//===----------------------------------------------------------------------===//
// VariableListItem Implementation
//===----------------------------------------------------------------------===//
void VariableListItem::CreateChildren(
wxTreeCtrl* tree, const wxTreeItemId & id) {
const Module::GlobalListType & vars = module_->getGlobalList();
for (Module::GlobalListType::const_iterator it = vars.begin(),
itEnd = vars.end();
it != itEnd; ++it) {
CreateChild(tree, id, new VariableItem(module_, it));
}
tree->SortChildren(id);
}
bool VariableListItem::CanCreateChildren() const {
return !module_->getGlobalList().empty();
}
//===----------------------------------------------------------------------===//
// AliasListItem Implementation
//===----------------------------------------------------------------------===//
void AliasListItem::CreateChildren(
wxTreeCtrl* tree, const wxTreeItemId & id) {
}
bool AliasListItem::CanCreateChildren() const {
return !module_->getAliasList().empty();
}
//===----------------------------------------------------------------------===//
// NamedMetaListItem Implementation
//===----------------------------------------------------------------------===//
void NamedMetaListItem::CreateChildren(
wxTreeCtrl* tree, const wxTreeItemId & id) {
typedef Module::const_named_metadata_iterator const_iterator;
for (const_iterator it = module_->named_metadata_begin(),
itEnd = module_->named_metadata_end();
it != itEnd; ++it) {
CreateChild(tree, id, new NamedMDNodeItem(module_, it));
}
tree->SortChildren(id);
}
bool NamedMetaListItem::CanCreateChildren() const {
return module_->named_metadata_begin() != module_->named_metadata_end();
}
//===----------------------------------------------------------------------===//
// TypeItem Implementation
//===----------------------------------------------------------------------===//
int TypeItem::GetIcon() const {
return Resources::ICON_TYPE;
}
wxString TypeItem::GetCaption() const {
wxStringOutputStream strm;
wxTextOutputStream tstrm(strm);
tstrm << typeName_ << _(" = ");
printTypeExpansion(tstrm, module_, type_, 1);
return strm.GetString();
}
void TypeItem::CreateChildren(wxTreeCtrl* tree, const wxTreeItemId & id) {
unsigned ct = type_->getNumContainedTypes();
for (unsigned i = 0; i < ct; ++i) {
CreateChild(tree, id, new TypeRefItem(module_, type_->getContainedType(i)));
}
}
bool TypeItem::CanCreateChildren() const {
return type_->getNumContainedTypes() > 0;
}
void TypeItem::ShowDetails(DetailsView* detailsView) {
}
//===----------------------------------------------------------------------===//
// TypeRefItem Implementation
//===----------------------------------------------------------------------===//
int TypeRefItem::GetIcon() const {
return Resources::ICON_TYPEREF;
}
wxString TypeRefItem::GetCaption() const {
wxStringOutputStream strm;
wxTextOutputStream tstrm(strm);
printType(tstrm, module_, type_, 1);
return strm.GetString();
}
void TypeRefItem::CreateChildren(wxTreeCtrl* tree, const wxTreeItemId & id) {
// Auto-deref pointer types
const Type* ty = type_;
if (isa<PointerType>(ty)) {
ty = ty->getContainedType(0);
}
unsigned ct = ty->getNumContainedTypes();
for (unsigned i = 0; i < ct; ++i) {
CreateChild(tree, id, new TypeRefItem(module_, ty->getContainedType(i)));
}
}
bool TypeRefItem::CanCreateChildren() const {
return type_->getNumContainedTypes() > 0;
}
void TypeRefItem::ShowDetails(DetailsView* detailsView) {
}
//===----------------------------------------------------------------------===//
// FunctionItem Implementation
//===----------------------------------------------------------------------===//
int FunctionItem::GetIcon() const {
return Resources::ICON_FUNCTION;
}
wxString FunctionItem::GetCaption() const {
wxStringOutputStream strm;
wxTextOutputStream tstrm(strm);
printType(tstrm, module_, function_->getFunctionType()->getReturnType(), 1);
tstrm << _(" ");
tstrm << toWxStr(function_->getName()) << _("(");
const Function::ArgumentListType & args = function_->getArgumentList();
for (Function::ArgumentListType::const_iterator it = args.begin(),
itEnd = args.end(); it != itEnd; ++it) {
if (it != args.begin()) {
tstrm << _(", ");
}
printType(tstrm, module_, it->getType(), 1);
}
tstrm << _(")");
// TODO: Function attributes?
return strm.GetString();
}
void FunctionItem::CreateChildren(wxTreeCtrl* tree, const wxTreeItemId & id) {
// Expand to params, possibly blocks.
}
bool FunctionItem::CanCreateChildren() const {
return false; // for now
}
void FunctionItem::ShowDetails(DetailsView* detailsView) {
detailsView->Add(_("Linkage"), GetLinkageName(function_->getLinkage()));
if (function_->hasGC()) {
detailsView->Add(_("GC"), function_->getGC());
}
wxArrayString attrs;
if (function_->doesNotReturn()) {
attrs.Add(_("NoReturn"));
}
if (function_->doesNotThrow()) {
attrs.Add(_("NoUnwind"));
}
if (function_->doesNotAccessMemory()) {
attrs.Add(_("ReadNone"));
}
if (function_->onlyReadsMemory()) {
attrs.Add(_("ReadOnly"));
}
if (function_->hasStructRetAttr()) {
attrs.Add(_("StructRet"));
}
if (attrs.GetCount() > 0) {
for (unsigned i = 0; i < attrs.GetCount(); ++i) {
if (i == 0) {
detailsView->Add(_("Attributes"), attrs[i]);
} else {
detailsView->Add(wxString(), attrs[i]);
}
}
}
}
//===----------------------------------------------------------------------===//
// VariableItem Implementation
//===----------------------------------------------------------------------===//
int VariableItem::GetIcon() const {
return Resources::ICON_VARIABLE;
}
wxString VariableItem::GetCaption() const {
return toWxStr(var_->getName());
}
void VariableItem::CreateChildren(wxTreeCtrl* tree, const wxTreeItemId & id) {
CreateChild(tree, id, new TypeRefItem(module_, var_->getType()));
if (var_->hasInitializer()) {
CreateChild(tree, id, new ConstantItem(module_, var_->getInitializer()));
}
}
bool VariableItem::CanCreateChildren() const {
return true;
}
void VariableItem::ShowDetails(DetailsView* detailsView) {
detailsView->Add(_("Linkage"), GetLinkageName(var_->getLinkage()));
}
//===----------------------------------------------------------------------===//
// ConstantItem Implementation
//===----------------------------------------------------------------------===//
int ConstantItem::GetIcon() const {
return Resources::ICON_CONSTANT;
}
wxString ConstantItem::GetCaption() const {
wxStringOutputStream strm;
wxTextOutputStream tstrm(strm);
printConstant(tstrm, module_, val_, 2);
return strm.GetString();
}
void ConstantItem::CreateChildren(wxTreeCtrl* tree, const wxTreeItemId & id) {
unsigned cnt = val_->getNumOperands();
for (unsigned i = 0; i < cnt; ++i) {
const Constant* v = cast<Constant>(val_->getOperand(i));
if (const GlobalVariable* gv = dyn_cast<GlobalVariable>(v)) {
// This should really be a 'VariableRefItem' that doesn't expand.
CreateChild(tree, id, new VariableItem(module_, gv));
} else if (const Function* fn = dyn_cast<Function>(v)) {
// This should really be a 'FunctionRefItem' that doesn't expand.
CreateChild(tree, id, new FunctionItem(module_, fn));
} else {
CreateChild(tree, id, new ConstantItem(
module_, cast<Constant>(val_->getOperand(i))));
}
}
}
bool ConstantItem::CanCreateChildren() const {
return val_->getNumOperands() > 0;
}
void ConstantItem::ShowDetails(DetailsView* detailsView) {
}
//===----------------------------------------------------------------------===//
// NamedMDNodeItem Implementation
//===----------------------------------------------------------------------===//
int NamedMDNodeItem::GetIcon() const {
return Resources::ICON_META;
}
wxString NamedMDNodeItem::GetCaption() const {
return toWxStr(node_->getName());
}
void NamedMDNodeItem::CreateChildren(
wxTreeCtrl* tree, const wxTreeItemId & id) {
unsigned ct = node_->getNumOperands();
for (unsigned i = 0; i < ct; ++i) {
CreateChild(tree, id, new MetadataNodeItem(module_, node_->getOperand(i)));
}
}
bool NamedMDNodeItem::CanCreateChildren() const {
return node_->getNumOperands() > 0;
}
void NamedMDNodeItem::ShowDetails(DetailsView* detailsView) {
}
//===----------------------------------------------------------------------===//
// MetadataNodeItem Implementation
//===----------------------------------------------------------------------===//
int MetadataNodeItem::GetIcon() const {
return Resources::ICON_META;
}
wxString MetadataNodeItem::GetCaption() const {
wxStringOutputStream strm;
wxTextOutputStream tstrm(strm);
printMetadata(tstrm, nodeVal_, 1);
return strm.GetString();
}
void MetadataNodeItem::CreateChildren(
wxTreeCtrl* tree, const wxTreeItemId & id) {
if (const MDNode* mn = dyn_cast<MDNode>(nodeVal_)) {
unsigned ct = mn->getNumOperands();
for (unsigned i = 0; i < ct; ++i) {
Value* v = mn->getOperand(i);
if (v == NULL) {
// ??? a null child node?
} else if (GlobalVariable* gv = dyn_cast<GlobalVariable>(v)) {
CreateChild(tree, id, new VariableItem(module_, gv));
} else if (Function* fn = dyn_cast<Function>(v)) {
CreateChild(tree, id, new FunctionItem(module_, fn));
} else if (Constant* c = dyn_cast<Constant>(v)) {
CreateChild(tree, id, new ConstantItem(module_, c));
} else {
CreateChild(tree, id, new MetadataNodeItem(module_, v));
}
}
}
}
bool MetadataNodeItem::CanCreateChildren() const {
if (const MDNode* mn = dyn_cast<MDNode>(nodeVal_)) {
return mn->getNumOperands() > 0;
}
return false;
}
void MetadataNodeItem::ShowDetails(DetailsView* detailsView) {
}
//===----------------------------------------------------------------------===//
// DebugSymbolsRootItem Implementation
//===----------------------------------------------------------------------===//
DebugSymbolsRootItem::DebugSymbolsRootItem(
const llvm::Module* module)
: ListItem(module)
{
diFinder_.processModule(*const_cast<Module *>(module));
}
void DebugSymbolsRootItem::CreateChildren(
wxTreeCtrl* tree, const wxTreeItemId & id) {
if (diFinder_.compile_unit_count() > 0) {
CreateChild(tree, id,
new DIEListItem(module_, _("Compile Units"),
diFinder_.compile_unit_begin(),
diFinder_.compile_unit_end()));
}
if (diFinder_.type_count() > 0) {
CreateChild(tree, id,
new DIETypeListItem(module_, _("Types"),
diFinder_.type_begin(),
diFinder_.type_end()));
}
if (diFinder_.global_variable_count() > 0) {
CreateChild(tree, id,
new DIEListItem(module_, _("Global Variables"),
diFinder_.global_variable_begin(),
diFinder_.global_variable_end()));
}
if (diFinder_.subprogram_count() > 0) {
CreateChild(tree, id,
new DIEListItem(module_, _("Subprograms"),
diFinder_.subprogram_begin(),
diFinder_.subprogram_end()));
}
}
bool DebugSymbolsRootItem::CanCreateChildren() const {
return diFinder_.compile_unit_count() > 0 ||
diFinder_.type_count() > 0 ||
diFinder_.global_variable_count() > 0 ||
diFinder_.subprogram_count() > 0;
}
//===----------------------------------------------------------------------===//
// DIEListItem Implementation
//===----------------------------------------------------------------------===//
void DIEListItem::CreateChildren(
wxTreeCtrl *tree, const wxTreeItemId& id) {
for (DebugInfoFinder::iterator it = nodeList_.begin(); it != nodeList_.end();
++it) {
CreateChild(tree, id, new DIEItem(module_, *it));
}
tree->SortChildren(id);
}
bool DIEListItem::CanCreateChildren() const {
return true;
}
//===----------------------------------------------------------------------===//
// DIETypeListItem Implementation
//===----------------------------------------------------------------------===//
void DIETypeListItem::CreateChildren(
wxTreeCtrl *tree, const wxTreeItemId& id) {
NodeList classTypes;
NodeList enumTypes;
NodeList structTypes;
NodeList otherTypes;
for (NodeList::const_iterator it = nodeList_.begin(); it != nodeList_.end();
++it) {
DIType diType(*it);
switch (diType.getTag()) {
case dwarf::DW_TAG_class_type:
classTypes.push_back(*it);
break;
case dwarf::DW_TAG_enumeration_type:
enumTypes.push_back(*it);
break;
case dwarf::DW_TAG_structure_type:
structTypes.push_back(*it);
break;
case dwarf::DW_TAG_base_type:
case dwarf::DW_TAG_inheritance:
case dwarf::DW_TAG_member:
case dwarf::DW_TAG_subroutine_type:
case dwarf::DW_TAG_union_type:
case dwarf::DW_TAG_array_type:
case dwarf::DW_TAG_pointer_type:
break;
default:
otherTypes.push_back(*it);
break;
}
}
if (!classTypes.empty()) {
CreateChild(tree, id,
new DIEListItem(module_, _("Class Types"),
classTypes.begin(),
classTypes.end()));
}
if (!enumTypes.empty()) {
CreateChild(tree, id,
new DIEListItem(module_, _("Enumeration Types"),
enumTypes.begin(),
enumTypes.end()));
}
if (!structTypes.empty()) {
CreateChild(tree, id,
new DIEListItem(module_, _("Structure Types"),
structTypes.begin(),
structTypes.end()));
}
if (!otherTypes.empty()) {
CreateChild(tree, id,
new DIEListItem(module_, _("Other Types"),
otherTypes.begin(),
otherTypes.end()));
}
tree->SortChildren(id);
}
//===----------------------------------------------------------------------===//
// DIEItem Implementation
//===----------------------------------------------------------------------===//
int DIEItem::GetIcon() const {
// TODO: Different icons for different DIE types.
return Resources::ICON_DEBUG;
}
wxString DIEItem::GetCaption() const {
using namespace dwarf;
wxStringOutputStream strm;
wxTextOutputStream tstrm(strm);
DIDescriptor diDesc(node_);
unsigned tag = diDesc.getTag();
tstrm << _("[") << GetDITagName(tag) << _("] ");
if (diDesc.isCompileUnit()) {
DICompileUnit diCU(node_);
tstrm << _(" ") << toWxStr(diCU.getFilename());
} else if (diDesc.isGlobalVariable()) {
DIGlobalVariable diVar(node_);
tstrm << _(" ") << toWxStr(diVar.getName());
} else if (diDesc.isSubprogram()) {
DISubprogram diSubprogram(node_);
tstrm << _(" ") << toWxStr(diSubprogram.getLinkageName());
} else if (diDesc.isCompositeType()) {
DICompositeType diCompType(node_);
tstrm << _(" ") << toWxStr(diCompType.getName());
} else if (diDesc.isDerivedType()) {
DIDerivedType diDerivedType(node_);
tstrm << _(" ");
FormatDIType(tstrm, diDerivedType);
} else if (diDesc.isBasicType()) {
DIBasicType diBasicType(node_);
tstrm << _(" ");
FormatDIType(tstrm, diBasicType);
} else if (diDesc.isEnumerator()) {
DIEnumerator diEnum(node_);
tstrm << _(" ") << toWxStr(diEnum.getName());
} else if (diDesc.isVariable()) {
DIVariable diVar(node_);
tstrm << _(" ") << toWxStr(diVar.getName());
}
return strm.GetString();
}
void DIEItem::CreateChildren(wxTreeCtrl *tree, const wxTreeItemId& id) {
DIDescriptor diDesc(node_);
if (diDesc.isCompileUnit()) {
CreateCompileUnitChildren(tree, id);
} else if (diDesc.isSubprogram()) {
CreateSubprogramChildren(tree, id);
} else if (diDesc.isGlobalVariable()) {
DIGlobalVariable diVar(node_);
CreateChild(tree, id, new DIEItem(module_, diVar.getType()));
} else if (diDesc.isCompositeType()) {
DICompositeType diCompType(node_);
DIArray typeArray = diCompType.getTypeArray();
unsigned ct = typeArray.getNumElements();
for (unsigned i = 0; i < ct; ++i) {
CreateChild(tree, id, new DIEItem(module_, typeArray.getElement(i)));
}
} else if (diDesc.isDerivedType()) {
DIDerivedType diDerivedType(node_);
CreateChild(tree, id,
new DIEItem(module_, diDerivedType.getTypeDerivedFrom()));
} else if (diDesc.isVariable()) {
DIVariable diVar(node_);
CreateChild(tree, id, new DIEItem(module_, diVar.getType()));
}
}
void DIEItem::CreateCompileUnitChildren(wxTreeCtrl *tree,
const wxTreeItemId& id) {
// It's expensive to rescan the entire module, but it's only done lazily.
DebugInfoFinder diFinder;
diFinder.processModule(*const_cast<Module *>(module_));
// CU-specific Types
if (diFinder.type_count() > 0) {
llvm::SmallVector<llvm::MDNode*, 32> cuTypes;
for (DebugInfoFinder::iterator it = diFinder.type_begin(),
itEnd = diFinder.type_end(); it != itEnd; ++it) {
DIType diType(*it);
if (diType.getCompileUnit() == node_) {
cuTypes.push_back(*it);
}
}
if (!cuTypes.empty()) {
CreateChild(tree, id, new DIETypeListItem(
module_, _("Types"), cuTypes.begin(), cuTypes.end()));
}
}
// CU-specific Global variables
if (diFinder.global_variable_count() > 0) {
llvm::SmallVector<llvm::MDNode*, 32> cuVariables;
for (DebugInfoFinder::iterator it = diFinder.global_variable_begin(),
itEnd = diFinder.global_variable_end(); it != itEnd; ++it) {
DIGlobalVariable diVar(*it);
if (diVar.getCompileUnit() == node_) {
cuVariables.push_back(*it);
}
}
if (!cuVariables.empty()) {
CreateChild(tree, id, new DIEListItem(
module_, _("Global Variables"),
cuVariables.begin(), cuVariables.end()));
}
}
// CU-specific Subprograms
if (diFinder.subprogram_count() > 0) {
llvm::SmallVector<llvm::MDNode*, 32> cuSubprograms;
for (DebugInfoFinder::iterator it = diFinder.subprogram_begin(),
itEnd = diFinder.subprogram_end(); it != itEnd; ++it) {
DISubprogram diSubprogram(*it);
if (diSubprogram.getCompileUnit() == node_) {
cuSubprograms.push_back(*it);
}
}
if (!cuSubprograms.empty()) {
CreateChild(tree, id, new DIEListItem(
module_, _("Subprograms"),
cuSubprograms.begin(), cuSubprograms.end()));
}
}
}
void DIEItem::CreateSubprogramChildren(wxTreeCtrl *tree,
const wxTreeItemId& id) {
DISubprogram diSubprogram(node_);
// Subroutine type
CreateChild(tree, id, new DIEItem(module_, diSubprogram.getType()));
// Lexical block search.
CreateLocalScopeChildren(tree, id, diSubprogram.getFunction(),
diSubprogram);
}
void DIEItem::CreateLocalScopeChildren(wxTreeCtrl *tree,
const wxTreeItemId& id,
const llvm::Function * fn, llvm::DIScope parent) {
// Walk all of the instructions of function fn, and find all lexical
// blocks whose parent is 'parent'.
llvm::SetVector<DILexicalBlock> blocks;
if (fn != NULL) {
for (Function::const_iterator it = fn->begin(), itEnd = fn->end();
it != itEnd; ++it) {
const BasicBlock & bb = *it;
for (BasicBlock::const_iterator j = bb.begin(), jEnd = bb.end();
j != jEnd; ++j) {
const Instruction & inst = *j;
// Get the debug location and find the lexical scope which is
// a child of 'parent'.
const DebugLoc& loc = inst.getDebugLoc();
DIScope diLocalScope(loc.getScope(module_->getContext()));
// If the instruction is in scope 'parent', then see if it's
// a variable.
if (const DbgDeclareInst* dd = dyn_cast<DbgDeclareInst>(&inst)) {
if (diLocalScope == parent) {
CreateChild(tree, id, new DIEItem(module_, dd->getVariable()));
}
} else if (const DbgValueInst* dv = dyn_cast<DbgValueInst>(&inst)) {
(void) dv;
//DIVariable diVar(di->getVariable());
}
// Walk up the chain of lexical blocks until we find one whose
// parent is 'parent', and then add it to the set.
while (diLocalScope.isLexicalBlock()) {
DILexicalBlock diBlock(diLocalScope);
DIScope context = diBlock.getContext();
if (context == parent) {
blocks.insert(diBlock);
break;
}
diLocalScope = context;
}
}
}
}
// Add all the lexical blocks we found as child items.
for (llvm::SetVector<DILexicalBlock>::const_iterator it = blocks.begin(),
itEnd = blocks.end(); it != itEnd; ++it) {
CreateChild(tree, id, new DIELexicalBlockItem(module_, *it, fn));
}
}
bool DIEItem::CanCreateChildren() const {
DIDescriptor diDesc(node_);
if (diDesc.isCompileUnit() ||
diDesc.isVariable() ||
diDesc.isGlobalVariable() ||
diDesc.isSubprogram() ||
diDesc.isDerivedType()) {
return true;
} else if (diDesc.isCompositeType()) {
DICompositeType diCompType(node_);
return diCompType.getTypeArray().getNumElements() > 0;
} else {
return false;
}
}
void DIEItem::ShowDetails(DetailsView* detailsView) {
DIDescriptor diDesc(node_);
unsigned tag = diDesc.getTag();
detailsView->Add(_("Tag"), GetDITagName(tag));
if (diDesc.isCompileUnit()) {
DICompileUnit diCU(node_);
detailsView->Add(_("DescriptorType"), _("DICompileUnit"));
detailsView->Add(_("Name"), diCU.getFilename());
detailsView->Add(_("Directory"), diCU.getDirectory());
detailsView->Add(_("Producer"), diCU.getProducer());
detailsView->Add(_("IsMain"), diCU.isMain());
detailsView->Add(_("IsOptimized"), diCU.isOptimized());
} else if (diDesc.isGlobalVariable()) {
DIGlobalVariable diVar(node_);
detailsView->Add(_("DescriptorType"), _("DIGlobalVariable"));
detailsView->Add(_("Name"), diVar.getName());
detailsView->Add(_("DisplayName"), diVar.getDisplayName());
detailsView->Add(_("LinkageName"), diVar.getLinkageName());
ShowCompileUnit(detailsView, diVar.getCompileUnit());
detailsView->Add(_("Line"), diVar.getLineNumber());
ShowContext(detailsView, diVar.getContext());
detailsView->Add(_("Type"), DITypeToString(diVar.getType()));
detailsView->Add(_("IsLocalToUnit"), (bool) diVar.isLocalToUnit());
detailsView->Add(_("IsDefinition"), (bool) diVar.isDefinition());
} else if (diDesc.isSubprogram()) {
DISubprogram diSubprogram(node_);
detailsView->Add(_("DescriptorType"), _("DISubprogram"));
detailsView->Add(_("Name"), diSubprogram.getName());
detailsView->Add(_("DisplayName"), diSubprogram.getDisplayName());
detailsView->Add(_("LinkageName"), diSubprogram.getLinkageName());
ShowCompileUnit(detailsView, diSubprogram.getCompileUnit());
detailsView->Add(_("Line"), diSubprogram.getLineNumber());
ShowContext(detailsView, diSubprogram.getContext());
detailsView->Add(_("Type"), DITypeToString(diSubprogram.getType()));
detailsView->Add(_("IsLocalToUnit"), diSubprogram.isLocalToUnit());
detailsView->Add(_("IsDefinition"), diSubprogram.isDefinition());
// TODO: Virtuality
// TODO: Virtual index
detailsView->Add(_("Artificial"), (bool) diSubprogram.isArtificial());
#if HAVE_LLVM_DISUBPROGRAM_IS_PRIVATE
detailsView->Add(_("Private"), diSubprogram.isPrivate());
detailsView->Add(_("Protected"), diSubprogram.isProtected());
detailsView->Add(_("Explicit"), diSubprogram.isExplicit());
detailsView->Add(_("Prototyped"), diSubprogram.isPrototyped());
#endif
} else if (diDesc.isEnumerator()) {
DIEnumerator diEnum(node_);
detailsView->Add(_("DescriptorType"), _("DIEnumerator"));
detailsView->Add(_("Name"), diEnum.getName());
// TODO: Enum value
} else if (diDesc.isCompositeType()) {
DICompositeType diCompType(node_);
detailsView->Add(_("DescriptorType"), _("DICompositeType"));
detailsView->Add(_("Name"), diCompType.getName());
ShowCompileUnit(detailsView, diCompType.getCompileUnit());
ShowFile(detailsView, diCompType.getFile());
detailsView->Add(_("Line"), diCompType.getLineNumber());
ShowContext(detailsView, diCompType.getContext());
detailsView->Add(_("Private"), diCompType.isPrivate());
detailsView->Add(_("Protected"), diCompType.isProtected());
detailsView->Add(_("Artificial"), diCompType.isArtificial());
detailsView->Add(_("Virtual"), diCompType.isVirtual());
detailsView->Add(_("ForwardDecl"), diCompType.isForwardDecl());
/*
DIFile getFile() const { return getFieldAs<DIFile>(3); }
uint64_t getSizeInBits() const { return getUInt64Field(5); }
uint64_t getAlignInBits() const { return getUInt64Field(6); }
*/
} else if (diDesc.isDerivedType()) {
DIDerivedType diDerivedType(node_);
DIType diBase(diDerivedType.getTypeDerivedFrom());
detailsView->Add(_("DescriptorType"), _("DIDerivedType"));
switch (diDerivedType.getTag()) {
case dwarf::DW_TAG_inheritance:
detailsView->Add(_("Type"), DITypeToString(diBase));
break;
case dwarf::DW_TAG_pointer_type:
case dwarf::DW_TAG_reference_type:
case dwarf::DW_TAG_const_type:
case dwarf::DW_TAG_volatile_type:
case dwarf::DW_TAG_restrict_type:
case dwarf::DW_TAG_typedef:
detailsView->Add(_("Type"), DITypeToString(diDerivedType));
break;
case dwarf::DW_TAG_member:
detailsView->Add(_("Name"), diDerivedType.getName());
detailsView->Add(_("Type"), DITypeToString(diBase));
break;
}
} else if (diDesc.isBasicType()) {
DIBasicType diBasicType(node_);
detailsView->Add(_("DescriptorType"), _("DIBasicType"));
const char * encodingName =
dwarf::AttributeEncodingString(diBasicType.getEncoding());
if (encodingName != NULL) {
detailsView->Add(_("Encoding"), wxString::From8BitData(encodingName));
}
} else if (diDesc.isVariable()) {
DIVariable diVar(node_);
detailsView->Add(_("DescriptorType"), _("DIVariable"));
detailsView->Add(_("Name"), diVar.getName());
ShowCompileUnit(detailsView, diVar.getCompileUnit());
detailsView->Add(_("Line"), diVar.getLineNumber());
ShowContext(detailsView, diVar.getContext());
detailsView->Add(_("Type"), DITypeToString(diVar.getType()));
}
}
void DIEItem::ShowCompileUnit(DetailsView* detailsView, DICompileUnit cu) {
detailsView->Add(_("CompileUnit"),
toWxStr(cu.getDirectory()) + _("/") + toWxStr(cu.getFilename()));
}
void DIEItem::ShowFile(DetailsView* detailsView, DIFile file) {
detailsView->Add(_("File"),
toWxStr(file.getDirectory()) + _("/") + toWxStr(file.getFilename()));
}
void DIEItem::ShowContext(DetailsView* detailsView, DIScope scope) {
// TODO: Fill out these cases.
if (scope.isCompileUnit()) {
DICompileUnit diCompileUnit(scope);
detailsView->Add(_("ContextType"), _("DICompileUnit"));
detailsView->Add(_("Context"),
toWxStr(diCompileUnit.getDirectory()) + _("/") +
toWxStr(diCompileUnit.getFilename()));
} else if (scope.isFile()) {
DIFile diFile(scope);
detailsView->Add(_("ContextType"), _("DIFile"));
detailsView->Add(_("Context"),
toWxStr(diFile.getDirectory()) + _("/") +
toWxStr(diFile.getFilename()));
} else if (scope.isNameSpace()) {
DINameSpace diNameSpace(scope);
detailsView->Add(_("ContextType"), _("DINameSpace"));
detailsView->Add(_("Context"), diNameSpace.getName());
} else if (scope.isSubprogram()) {
DISubprogram diSubprogram(scope);
detailsView->Add(_("ContextType"), _("DISubprogram"));
detailsView->Add(_("Context"), diSubprogram.getName());
} else if (scope.isLexicalBlock()) {
detailsView->Add(_("ContextType"), _("DILexicalBlock"));
// TODO: Implement context name.
detailsView->Add(_("Context"), _("?{}"));
} else if (scope.isType()) {
detailsView->Add(_("ContextType"), _("DIType"));
detailsView->Add(_("Context"), DITypeToString(DIType(scope)));
} else {
detailsView->Add(_("Context"), _("??? [Unknown]"));
}
}
wxString DIEItem::DITypeToString(DIType type) const {
wxStringOutputStream strm;
wxTextOutputStream tstrm(strm);
FormatDIType(tstrm, type);
return strm.GetString();
}
void DIEItem::FormatDIType(wxTextOutputStream& out, DIType type) const {
if (type.isCompositeType()) {
DICompositeType diCompType(type);
if (!type.getName().empty()) {
out << toWxStr(type.getName());
} else {
out << _("?Implement unnamed composite");
// TODO: Implement:
// DW_TAG_array_type
// DW_TAG_enumeration_type
// DW_TAG_structure_type
// DW_TAG_union_type
// DW_TAG_vector_type
// DW_TAG_subroutine_type
// DW_TAG_inheritance
}
} else if (type.isDerivedType()) {
DIDerivedType diDerivedType(type);
DIType diBase = diDerivedType.getTypeDerivedFrom();
switch (diDerivedType.getTag()) {
case dwarf::DW_TAG_inheritance:
FormatDIType(out, diBase);
break;
case dwarf::DW_TAG_pointer_type:
FormatDIType(out, diBase);
out << _("*");
break;
case dwarf::DW_TAG_array_type:
FormatDIType(out, diBase);
// TODO: Get the array size, use LLVM array notation.
out << _("[]");
break;
case dwarf::DW_TAG_member:
out << toWxStr(diDerivedType.getName());
break;
case dwarf::DW_TAG_reference_type:
case dwarf::DW_TAG_const_type:
case dwarf::DW_TAG_volatile_type:
case dwarf::DW_TAG_restrict_type:
case dwarf::DW_TAG_typedef:
// TODO: Implement
break;
}
} else if (type.isBasicType()) {
DIBasicType diBasicType(type);
const char * encodingName =
dwarf::AttributeEncodingString(diBasicType.getEncoding());
if (encodingName != NULL) {
out << toWxStr(encodingName);
}
}
}
//===----------------------------------------------------------------------===//
// DIELexicalBlockItem Implementation
//===----------------------------------------------------------------------===//
wxString DIELexicalBlockItem::GetCaption() const {
return _("LexicalBlock");
}
void DIELexicalBlockItem::CreateChildren(wxTreeCtrl* tree,
const wxTreeItemId& id) {
}
bool DIELexicalBlockItem::CanCreateChildren() const {
return false;
}
void DIELexicalBlockItem::ShowDetails(DetailsView* detailsView) {
}