diff options
Diffstat (limited to 'lldb/source/Symbol')
-rw-r--r-- | lldb/source/Symbol/Block.cpp | 641 | ||||
-rw-r--r-- | lldb/source/Symbol/ClangASTContext.cpp | 2552 | ||||
-rw-r--r-- | lldb/source/Symbol/CompileUnit.cpp | 366 | ||||
-rw-r--r-- | lldb/source/Symbol/DWARFCallFrameInfo.cpp | 1344 | ||||
-rw-r--r-- | lldb/source/Symbol/Declaration.cpp | 172 | ||||
-rw-r--r-- | lldb/source/Symbol/Function.cpp | 432 | ||||
-rw-r--r-- | lldb/source/Symbol/LineEntry.cpp | 237 | ||||
-rw-r--r-- | lldb/source/Symbol/LineTable.cpp | 332 | ||||
-rw-r--r-- | lldb/source/Symbol/ObjectFile.cpp | 92 | ||||
-rw-r--r-- | lldb/source/Symbol/Symbol.cpp | 463 | ||||
-rw-r--r-- | lldb/source/Symbol/SymbolContext.cpp | 424 | ||||
-rw-r--r-- | lldb/source/Symbol/SymbolFile.cpp | 50 | ||||
-rw-r--r-- | lldb/source/Symbol/SymbolVendor.mm | 386 | ||||
-rw-r--r-- | lldb/source/Symbol/Symtab.cpp | 596 | ||||
-rw-r--r-- | lldb/source/Symbol/Type.cpp | 1531 | ||||
-rw-r--r-- | lldb/source/Symbol/TypeList.cpp | 239 | ||||
-rw-r--r-- | lldb/source/Symbol/Variable.cpp | 167 | ||||
-rw-r--r-- | lldb/source/Symbol/VariableList.cpp | 116 |
18 files changed, 10140 insertions, 0 deletions
diff --git a/lldb/source/Symbol/Block.cpp b/lldb/source/Symbol/Block.cpp new file mode 100644 index 00000000000..321411940f4 --- /dev/null +++ b/lldb/source/Symbol/Block.cpp @@ -0,0 +1,641 @@ +//===-- Block.cpp -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Symbol/Block.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/Section.h" +#include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Symbol/VariableList.h" + +using namespace lldb; +using namespace lldb_private; + +Block::Block(user_id_t uid, uint32_t depth, BlockList* blocks) : + UserID(uid), + m_block_list(blocks), + m_depth(depth), + m_ranges(), + m_inlineInfoSP(), + m_variables() +{ +} + +Block::Block(const Block& rhs) : + UserID(rhs), + m_block_list(rhs.m_block_list), + m_depth(rhs.m_depth), + m_ranges(rhs.m_ranges), + m_inlineInfoSP(rhs.m_inlineInfoSP), + m_variables(rhs.m_variables) +{ +} + +const Block& +Block::operator= (const Block& rhs) +{ + if (this != &rhs) + { + UserID::operator= (rhs); + m_block_list = rhs.m_block_list; + m_depth = rhs.m_depth; + m_ranges = rhs.m_ranges; + m_inlineInfoSP = rhs.m_inlineInfoSP; + m_variables = rhs.m_variables; + } + return *this; +} + +Block::~Block () +{ +} + +void +Block::Dump(Stream *s, addr_t base_addr, int32_t depth, bool show_context) const +{ + if (depth < 0) + { + // We have a depth that is less than zero, print our parent blocks + // first + m_block_list->Dump(s, GetParentUID(), depth + 1, show_context); + } + + s->Printf("%.*p: ", (int)sizeof(void*) * 2, this); + s->Indent(); + *s << "Block" << ((const UserID&)*this); + user_id_t parentID = GetParentUID(); + const Block* parent_block = NULL; + if (parentID != Block::InvalidID) + { + parent_block = m_block_list->GetBlockByID(parentID); + s->Printf(", parent = {0x%8.8x}", parentID); + } + if (m_inlineInfoSP.get() != NULL) + m_inlineInfoSP->Dump(s); + + if (!m_ranges.empty()) + { + *s << ", ranges ="; + std::vector<VMRange>::const_iterator pos; + std::vector<VMRange>::const_iterator end = m_ranges.end(); + for (pos = m_ranges.begin(); pos != end; ++pos) + { + if (parent_block != NULL && parent_block->Contains(*pos) == false) + *s << '!'; + else + *s << ' '; + pos->Dump(s, base_addr); + } + } + s->EOL(); + + if (depth > 0) + { + s->IndentMore(); + + if (m_variables.get()) + { + m_variables->Dump(s, show_context); + } + + uint32_t blockID = m_block_list->GetFirstChild(GetID()); + while (blockID != Block::InvalidID) + { + m_block_list->Dump(s, blockID, depth - 1, show_context); + + blockID = m_block_list->GetSibling(blockID); + } + + s->IndentLess(); + } + +} + + +void +Block::CalculateSymbolContext(SymbolContext* sc) +{ + sc->block = this; + m_block_list->GetFunction()->CalculateSymbolContext(sc); +} + +void +Block::DumpStopContext (Stream *s, const SymbolContext *sc) +{ + user_id_t parentID = GetParentUID(); + Block* parent_block = NULL; + if (parentID != Block::InvalidID) + parent_block = m_block_list->GetBlockByID(parentID); + + InlineFunctionInfo* inline_info = InlinedFunctionInfo (); + if (inline_info) + { + const Declaration &call_site = inline_info->GetCallSite(); + if (sc) + { + // First frame, dump the first inline call site +// if (call_site.IsValid()) +// { +// s->PutCString(" at "); +// call_site.DumpStopContext (s); +// } + s->PutCString (" [inlined]"); + } + s->EOL(); + inline_info->DumpStopContext (s); + if (sc == NULL) + { + if (call_site.IsValid()) + { + s->PutCString(" at "); + call_site.DumpStopContext (s); + } + } + } + + if (sc) + { + // If we have any inlined functions, this will be the deepest most + // inlined location + if (sc->line_entry.IsValid()) + { + s->PutCString(" at "); + sc->line_entry.DumpStopContext (s); + } + } + if (parent_block) + parent_block->Block::DumpStopContext (s, NULL); +} + + +void +Block::DumpSymbolContext(Stream *s) +{ + m_block_list->GetFunction()->DumpSymbolContext(s); + s->Printf(", Block{0x%8.8x}", GetID()); +} + +bool +Block::Contains (addr_t range_offset) const +{ + return VMRange::ContainsValue(m_ranges, range_offset); +} + +bool +Block::Contains (const VMRange& range) const +{ + return VMRange::ContainsRange(m_ranges, range); +} + + + +bool +BlockList::BlockContainsBlockWithID (const user_id_t block_id, const user_id_t find_block_id) const +{ + if (block_id == Block::InvalidID) + return false; + + if (block_id == find_block_id) + return true; + else + { + user_id_t child_block_id = GetFirstChild(block_id); + while (child_block_id != Block::InvalidID) + { + if (BlockContainsBlockWithID (child_block_id, find_block_id)) + return true; + child_block_id = GetSibling(child_block_id); + } + } + + return false; +} + +bool +Block::ContainsBlockWithID (user_id_t block_id) const +{ + return m_block_list->BlockContainsBlockWithID (GetID(), block_id); +} + + +void +Block::AddRange(addr_t start_offset, addr_t end_offset) +{ + m_ranges.resize(m_ranges.size()+1); + m_ranges.back().Reset(start_offset, end_offset); +} + +InlineFunctionInfo* +Block::InlinedFunctionInfo () +{ + return m_inlineInfoSP.get(); +} + +const InlineFunctionInfo* +Block::InlinedFunctionInfo () const +{ + return m_inlineInfoSP.get(); +} + +// Return the current number of bytes that this object occupies in memory +size_t +Block::MemorySize() const +{ + size_t mem_size = sizeof(Block) + m_ranges.size() * sizeof(VMRange); + if (m_inlineInfoSP.get()) + mem_size += m_inlineInfoSP->MemorySize(); + if (m_variables.get()) + mem_size += m_variables->MemorySize(); + return mem_size; + +} + +user_id_t +Block::GetParentUID() const +{ + return m_block_list->GetParent(GetID()); +} + +user_id_t +Block::GetSiblingUID() const +{ + return m_block_list->GetSibling(GetID()); +} + +user_id_t +Block::GetFirstChildUID() const +{ + return m_block_list->GetFirstChild(GetID()); +} + +user_id_t +Block::AddChild(user_id_t userID) +{ + return m_block_list->AddChild(GetID(), userID); +} + +void +Block::SetInlinedFunctionInfo(const char *name, const char *mangled, const Declaration *decl_ptr, const Declaration *call_decl_ptr) +{ + m_inlineInfoSP.reset(new InlineFunctionInfo(name, mangled, decl_ptr, call_decl_ptr)); +} + +BlockList::BlockList(Function *function, const AddressRange& range) : + m_function(function), + m_range(range), + m_blocks() +{ +} + +BlockList::~BlockList() +{ +} + +AddressRange & +BlockList::GetAddressRange() +{ + return m_range; +} + +const AddressRange & +BlockList::GetAddressRange() const +{ + return m_range; +} + +void +BlockList::Dump(Stream *s, user_id_t blockID, uint32_t depth, bool show_context) const +{ + const Block* block = GetBlockByID(blockID); + if (block) + block->Dump(s, m_range.GetBaseAddress().GetFileAddress(), depth, show_context); +} + +Function * +BlockList::GetFunction() +{ + return m_function; +} + + +const Function * +BlockList::GetFunction() const +{ + return m_function; +} + +user_id_t +BlockList::GetParent(user_id_t blockID) const +{ + collection::const_iterator end = m_blocks.end(); + collection::const_iterator begin = m_blocks.begin(); + collection::const_iterator pos = std::find_if(begin, end, UserID::IDMatches(blockID)); + + if (pos != end && pos != begin && pos->Depth() > 0) + { + const uint32_t parent_depth = pos->Depth() - 1; + + while (--pos >= begin) + { + if (pos->Depth() == parent_depth) + return pos->GetID(); + } + } + return Block::InvalidID; +} + +user_id_t +BlockList::GetSibling(user_id_t blockID) const +{ + collection::const_iterator end = m_blocks.end(); + collection::const_iterator pos = std::find_if(m_blocks.begin(), end, UserID::IDMatches(blockID)); + + if (pos != end) + { + const uint32_t sibling_depth = pos->Depth(); + while (++pos != end) + { + uint32_t depth = pos->Depth(); + if (depth == sibling_depth) + return pos->GetID(); + if (depth < sibling_depth) + break; + } + } + return Block::InvalidID; +} + +user_id_t +BlockList::GetFirstChild(user_id_t blockID) const +{ + if (!m_blocks.empty()) + { + if (blockID == Block::RootID) + { + return m_blocks.front().GetID(); + } + else + { + collection::const_iterator end = m_blocks.end(); + collection::const_iterator pos = std::find_if(m_blocks.begin(), end, UserID::IDMatches(blockID)); + + if (pos != end) + { + collection::const_iterator child_pos = pos + 1; + if (child_pos != end) + { + if (child_pos->Depth() == pos->Depth() + 1) + return child_pos->GetID(); + } + } + } + } + return Block::InvalidID; +} + + +// Return the current number of bytes that this object occupies in memory +size_t +BlockList::MemorySize() const +{ + size_t mem_size = sizeof(BlockList); + + collection::const_iterator pos, end = m_blocks.end(); + for (pos = m_blocks.begin(); pos != end; ++pos) + mem_size += pos->MemorySize(); // Each block can vary in size + + return mem_size; + +} + +user_id_t +BlockList::AddChild (user_id_t parentID, user_id_t childID) +{ + bool added = false; + if (parentID == Block::RootID) + { + assert(m_blocks.empty()); + Block block(childID, 0, this); + m_blocks.push_back(block); + added = true; + } + else + { + collection::iterator end = m_blocks.end(); + collection::iterator parent_pos = std::find_if(m_blocks.begin(), end, UserID::IDMatches(parentID)); + assert(parent_pos != end); + if (parent_pos != end) + { + const uint32_t parent_sibling_depth = parent_pos->Depth(); + + collection::iterator insert_pos = parent_pos; + collection::iterator prev_sibling = end; + while (++insert_pos != end) + { + if (insert_pos->Depth() <= parent_sibling_depth) + break; + } + + Block child_block(childID, parent_pos->Depth() + 1, this); + collection::iterator child_pos = m_blocks.insert(insert_pos, child_block); + added = true; + } + } + if (added) + return childID; + return Block::InvalidID; +} + +const Block * +BlockList::GetBlockByID(user_id_t blockID) const +{ + if (m_blocks.empty()) + return NULL; + + if (blockID == Block::RootID) + blockID = m_blocks.front().GetID(); + + collection::const_iterator end = m_blocks.end(); + collection::const_iterator pos = std::find_if(m_blocks.begin(), end, UserID::IDMatches(blockID)); + if (pos != end) + return &(*pos); + return NULL; +} + +Block * +BlockList::GetBlockByID(user_id_t blockID) +{ + if (m_blocks.empty()) + return NULL; + + if (blockID == Block::RootID) + blockID = m_blocks.front().GetID(); + + collection::iterator end = m_blocks.end(); + collection::iterator pos = std::find_if(m_blocks.begin(), end, UserID::IDMatches(blockID)); + if (pos != end) + return &(*pos); + return NULL; +} + +bool +BlockList::AddRange(user_id_t blockID, addr_t start_offset, addr_t end_offset) +{ + Block *block = GetBlockByID(blockID); + + if (block) + { + block->AddRange(start_offset, end_offset); + return true; + } + return false; +} +// +//const Block * +//BlockList::FindDeepestBlockForAddress (const Address &addr) +//{ +// if (m_range.Contains(addr)) +// { +// addr_t block_offset = addr.GetFileAddress() - m_range.GetBaseAddress().GetFileAddress(); +// collection::const_iterator pos, end = m_blocks.end(); +// collection::const_iterator deepest_match_pos = end; +// for (pos = m_blocks.begin(); pos != end; ++pos) +// { +// if (pos->Contains (block_offset)) +// { +// if (deepest_match_pos == end || deepest_match_pos->Depth() < pos->Depth()) +// deepest_match_pos = pos; +// } +// } +// if (deepest_match_pos != end) +// return &(*deepest_match_pos); +// } +// return NULL; +//} +// +bool +BlockList::SetInlinedFunctionInfo(user_id_t blockID, const char *name, const char *mangled, const Declaration *decl_ptr, const Declaration *call_decl_ptr) +{ + Block *block = GetBlockByID(blockID); + + if (block) + { + block->SetInlinedFunctionInfo(name, mangled, decl_ptr, call_decl_ptr); + return true; + } + return false; +} + +VariableListSP +BlockList::GetVariableList(user_id_t blockID, bool get_child_variables, bool can_create) +{ + VariableListSP variable_list_sp; + Block *block = GetBlockByID(blockID); + if (block) + variable_list_sp = block->GetVariableList(get_child_variables, can_create); + return variable_list_sp; +} + +bool +BlockList::IsEmpty() const +{ + return m_blocks.empty(); +} + + + +bool +BlockList::SetVariableList(user_id_t blockID, VariableListSP& variables) +{ + Block *block = GetBlockByID(blockID); + if (block) + { + block->SetVariableList(variables); + return true; + } + return false; + +} + + +VariableListSP +Block::GetVariableList (bool get_child_variables, bool can_create) +{ + VariableListSP variable_list_sp; + if (m_variables.get() == NULL && can_create) + { + SymbolContext sc; + CalculateSymbolContext(&sc); + assert(sc.module_sp); + sc.module_sp->GetSymbolVendor()->ParseVariablesForContext(sc); + } + + if (m_variables.get()) + { + variable_list_sp.reset(new VariableList()); + if (variable_list_sp.get()) + variable_list_sp->AddVariables(m_variables.get()); + + if (get_child_variables) + { + user_id_t block_id = GetFirstChildUID(); + while (block_id != Block::InvalidID) + { + Block *child_block = m_block_list->GetBlockByID(block_id); + assert(child_block); + VariableListSP child_block_variable_list(child_block->GetVariableList(get_child_variables, can_create)); + if (child_block_variable_list.get()) + variable_list_sp->AddVariables(child_block_variable_list.get()); + + block_id = child_block->GetSiblingUID(); + } + } + } + + return variable_list_sp; +} + +uint32_t +Block::AppendVariables (bool can_create, bool get_parent_variables, VariableList *variable_list) +{ + uint32_t num_variables_added = 0; + VariableListSP variable_list_sp(GetVariableList(false, can_create)); + + if (variable_list_sp.get()) + { + num_variables_added = variable_list_sp->GetSize(); + variable_list->AddVariables(variable_list_sp.get()); + } + + if (get_parent_variables) + { + user_id_t parentID = GetParentUID(); + if (parentID != Block::InvalidID) + { + Block* parent_block = m_block_list->GetBlockByID(parentID); + if (parent_block) + num_variables_added += parent_block->AppendVariables (can_create, get_parent_variables, variable_list); + } + } + return num_variables_added; +} + + +void +Block::SetVariableList(VariableListSP& variables) +{ + m_variables = variables; +} + +uint32_t +Block::Depth () const +{ + return m_depth; +} + diff --git a/lldb/source/Symbol/ClangASTContext.cpp b/lldb/source/Symbol/ClangASTContext.cpp new file mode 100644 index 00000000000..be63de20c4c --- /dev/null +++ b/lldb/source/Symbol/ClangASTContext.cpp @@ -0,0 +1,2552 @@ +//===-- ClangASTContext.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ClangASTContext.h" + +// C Includes +// C++ Includes +#include <string> + +// Other libraries and framework includes +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTImporter.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/Type.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "clang/Frontend/FrontendOptions.h" +#include "clang/Frontend/LangStandard.h" + +// Project includes +#include "lldb/Core/dwarf.h" + +using namespace lldb_private; +using namespace llvm; +using namespace clang; + + +static void +ParseLangArgs +( + LangOptions &Opts, + FrontendOptions::InputKind IK +) +{ + // FIXME: Cleanup per-file based stuff. + + // Set some properties which depend soley on the input kind; it would be nice + // to move these to the language standard, and have the driver resolve the + // input kind + language standard. + if (IK == FrontendOptions::IK_Asm) { + Opts.AsmPreprocessor = 1; + } else if (IK == FrontendOptions::IK_ObjC || + IK == FrontendOptions::IK_ObjCXX || + IK == FrontendOptions::IK_PreprocessedObjC || + IK == FrontendOptions::IK_PreprocessedObjCXX) { + Opts.ObjC1 = Opts.ObjC2 = 1; + } + + LangStandard::Kind LangStd = LangStandard::lang_unspecified; + + if (LangStd == LangStandard::lang_unspecified) { + // Based on the base language, pick one. + switch (IK) { + case FrontendOptions::IK_None: + case FrontendOptions::IK_AST: + assert(0 && "Invalid input kind!"); + case FrontendOptions::IK_OpenCL: + LangStd = LangStandard::lang_opencl; + break; + case FrontendOptions::IK_Asm: + case FrontendOptions::IK_C: + case FrontendOptions::IK_PreprocessedC: + case FrontendOptions::IK_ObjC: + case FrontendOptions::IK_PreprocessedObjC: + LangStd = LangStandard::lang_gnu99; + break; + case FrontendOptions::IK_CXX: + case FrontendOptions::IK_PreprocessedCXX: + case FrontendOptions::IK_ObjCXX: + case FrontendOptions::IK_PreprocessedObjCXX: + LangStd = LangStandard::lang_gnucxx98; + break; + } + } + + const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd); + Opts.BCPLComment = Std.hasBCPLComments(); + Opts.C99 = Std.isC99(); + Opts.CPlusPlus = Std.isCPlusPlus(); + Opts.CPlusPlus0x = Std.isCPlusPlus0x(); + Opts.Digraphs = Std.hasDigraphs(); + Opts.GNUMode = Std.isGNUMode(); + Opts.GNUInline = !Std.isC99(); + Opts.HexFloats = Std.hasHexFloats(); + Opts.ImplicitInt = Std.hasImplicitInt(); + + // OpenCL has some additional defaults. + if (LangStd == LangStandard::lang_opencl) { + Opts.OpenCL = 1; + Opts.AltiVec = 1; + Opts.CXXOperatorNames = 1; + Opts.LaxVectorConversions = 1; + } + + // OpenCL and C++ both have bool, true, false keywords. + Opts.Bool = Opts.OpenCL || Opts.CPlusPlus; + +// if (Opts.CPlusPlus) +// Opts.CXXOperatorNames = !Args.hasArg(OPT_fno_operator_names); +// +// if (Args.hasArg(OPT_fobjc_gc_only)) +// Opts.setGCMode(LangOptions::GCOnly); +// else if (Args.hasArg(OPT_fobjc_gc)) +// Opts.setGCMode(LangOptions::HybridGC); +// +// if (Args.hasArg(OPT_print_ivar_layout)) +// Opts.ObjCGCBitmapPrint = 1; +// +// if (Args.hasArg(OPT_faltivec)) +// Opts.AltiVec = 1; +// +// if (Args.hasArg(OPT_pthread)) +// Opts.POSIXThreads = 1; +// +// llvm::StringRef Vis = getLastArgValue(Args, OPT_fvisibility, +// "default"); +// if (Vis == "default") + Opts.setVisibilityMode(LangOptions::Default); +// else if (Vis == "hidden") +// Opts.setVisibilityMode(LangOptions::Hidden); +// else if (Vis == "protected") +// Opts.setVisibilityMode(LangOptions::Protected); +// else +// Diags.Report(diag::err_drv_invalid_value) +// << Args.getLastArg(OPT_fvisibility)->getAsString(Args) << Vis; + +// Opts.OverflowChecking = Args.hasArg(OPT_ftrapv); + + // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs + // is specified, or -std is set to a conforming mode. + Opts.Trigraphs = !Opts.GNUMode; +// if (Args.hasArg(OPT_trigraphs)) +// Opts.Trigraphs = 1; +// +// Opts.DollarIdents = Args.hasFlag(OPT_fdollars_in_identifiers, +// OPT_fno_dollars_in_identifiers, +// !Opts.AsmPreprocessor); +// Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings); +// Opts.Microsoft = Args.hasArg(OPT_fms_extensions); +// Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings); +// if (Args.hasArg(OPT_fno_lax_vector_conversions)) +// Opts.LaxVectorConversions = 0; +// Opts.Exceptions = Args.hasArg(OPT_fexceptions); +// Opts.RTTI = !Args.hasArg(OPT_fno_rtti); +// Opts.Blocks = Args.hasArg(OPT_fblocks); +// Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char); +// Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar); +// Opts.Freestanding = Args.hasArg(OPT_ffreestanding); +// Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding; +// Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new); +// Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions); +// Opts.AccessControl = Args.hasArg(OPT_faccess_control); +// Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors); +// Opts.MathErrno = !Args.hasArg(OPT_fno_math_errno); +// Opts.InstantiationDepth = getLastArgIntValue(Args, OPT_ftemplate_depth, 99, +// Diags); +// Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime); +// Opts.ObjCConstantStringClass = getLastArgValue(Args, +// OPT_fconstant_string_class); +// Opts.ObjCNonFragileABI = Args.hasArg(OPT_fobjc_nonfragile_abi); +// Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior); +// Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls); +// Opts.PICLevel = getLastArgIntValue(Args, OPT_pic_level, 0, Diags); +// Opts.Static = Args.hasArg(OPT_static_define); + Opts.OptimizeSize = 0; + + // FIXME: Eliminate this dependency. +// unsigned Opt = +// Args.hasArg(OPT_Os) ? 2 : getLastArgIntValue(Args, OPT_O, 0, Diags); +// Opts.Optimize = Opt != 0; + unsigned Opt = 0; + + // This is the __NO_INLINE__ define, which just depends on things like the + // optimization level and -fno-inline, not actually whether the backend has + // inlining enabled. + // + // FIXME: This is affected by other options (-fno-inline). + Opts.NoInline = !Opt; + +// unsigned SSP = getLastArgIntValue(Args, OPT_stack_protector, 0, Diags); +// switch (SSP) { +// default: +// Diags.Report(diag::err_drv_invalid_value) +// << Args.getLastArg(OPT_stack_protector)->getAsString(Args) << SSP; +// break; +// case 0: Opts.setStackProtectorMode(LangOptions::SSPOff); break; +// case 1: Opts.setStackProtectorMode(LangOptions::SSPOn); break; +// case 2: Opts.setStackProtectorMode(LangOptions::SSPReq); break; +// } +} + +//---------------------------------------------------------------------- +// ClangASTContext constructor +//---------------------------------------------------------------------- +//ClangASTContext::ClangASTContext(Module *module) : +// m_target_triple(), +// m_ast_context_ap(), +// m_language_options_ap(), +// m_source_manager_ap(), +// m_target_info_ap(), +// m_identifier_table_ap(), +// m_selector_table_ap(), +// m_builtins_ap() +//{ +// if (module) +// { +// ObjectFile * objfile = module->GetObjectFile(); +// if (objfile) +// objfile->GetTargetTriple(m_target_triple); +// } +//} + +//ClangASTContext::ClangASTContext(const ConstString& target_triple) : +// m_target_triple(target_triple), +// m_ast_context_ap(), +// m_language_options_ap(), +// m_source_manager_ap(), +// m_target_info_ap(), +// m_identifier_table_ap(), +// m_selector_table_ap(), +// m_builtins_ap() +//{ +//} +ClangASTContext::ClangASTContext(const char *target_triple) : + m_target_triple(), + m_ast_context_ap(), + m_language_options_ap(), + m_source_manager_ap(), + m_diagnostic_ap(), + m_target_options_ap(), + m_target_info_ap(), + m_identifier_table_ap(), + m_selector_table_ap(), + m_builtins_ap() +{ + if (target_triple && target_triple[0]) + m_target_triple.assign (target_triple); +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +ClangASTContext::~ClangASTContext() +{ + m_builtins_ap.reset(); + m_selector_table_ap.reset(); + m_identifier_table_ap.reset(); + m_target_info_ap.reset(); + m_target_options_ap.reset(); + m_diagnostic_ap.reset(); + m_source_manager_ap.reset(); + m_language_options_ap.reset(); + m_ast_context_ap.reset(); +} + + +void +ClangASTContext::Clear() +{ + m_ast_context_ap.reset(); + m_language_options_ap.reset(); + m_source_manager_ap.reset(); + m_diagnostic_ap.reset(); + m_target_options_ap.reset(); + m_target_info_ap.reset(); + m_identifier_table_ap.reset(); + m_selector_table_ap.reset(); + m_builtins_ap.reset(); +} + +const char * +ClangASTContext::GetTargetTriple () +{ + return m_target_triple.c_str(); +} + +void +ClangASTContext::SetTargetTriple (const char *target_triple) +{ + Clear(); + m_target_triple.assign(target_triple); +} + + +ASTContext * +ClangASTContext::getASTContext() +{ + if (m_ast_context_ap.get() == NULL) + { + m_ast_context_ap.reset( + new ASTContext( + *getLanguageOptions(), + *getSourceManager(), + *getTargetInfo(), + *getIdentifierTable(), + *getSelectorTable(), + *getBuiltinContext())); + } + return m_ast_context_ap.get(); +} + +Builtin::Context * +ClangASTContext::getBuiltinContext() +{ + if (m_builtins_ap.get() == NULL) + m_builtins_ap.reset (new Builtin::Context(*getTargetInfo())); + return m_builtins_ap.get(); +} + +IdentifierTable * +ClangASTContext::getIdentifierTable() +{ + if (m_identifier_table_ap.get() == NULL) + m_identifier_table_ap.reset(new IdentifierTable (*ClangASTContext::getLanguageOptions(), NULL)); + return m_identifier_table_ap.get(); +} + +LangOptions * +ClangASTContext::getLanguageOptions() +{ + if (m_language_options_ap.get() == NULL) + { + m_language_options_ap.reset(new LangOptions()); + ParseLangArgs(*m_language_options_ap, FrontendOptions::IK_ObjCXX); +// InitializeLangOptions(*m_language_options_ap, FrontendOptions::IK_ObjCXX); + } + return m_language_options_ap.get(); +} + +SelectorTable * +ClangASTContext::getSelectorTable() +{ + if (m_selector_table_ap.get() == NULL) + m_selector_table_ap.reset (new SelectorTable()); + return m_selector_table_ap.get(); +} + +SourceManager * +ClangASTContext::getSourceManager() +{ + if (m_source_manager_ap.get() == NULL) + m_source_manager_ap.reset(new SourceManager(*getDiagnostic())); + return m_source_manager_ap.get(); +} + +Diagnostic * +ClangASTContext::getDiagnostic() +{ + if (m_diagnostic_ap.get() == NULL) + m_diagnostic_ap.reset(new Diagnostic()); + return m_diagnostic_ap.get(); +} + +TargetOptions * +ClangASTContext::getTargetOptions() +{ + if (m_target_options_ap.get() == NULL && !m_target_triple.empty()) + { + m_target_options_ap.reset (new TargetOptions()); + if (m_target_options_ap.get()) + m_target_options_ap->Triple = m_target_triple; + } + return m_target_options_ap.get(); +} + + +TargetInfo * +ClangASTContext::getTargetInfo() +{ + // target_triple should be something like "x86_64-apple-darwin10" + if (m_target_info_ap.get() == NULL && !m_target_triple.empty()) + m_target_info_ap.reset (TargetInfo::CreateTargetInfo(*getDiagnostic(), *getTargetOptions())); + return m_target_info_ap.get(); +} + +#pragma mark Basic Types + +static inline bool +QualTypeMatchesBitSize(const uint64_t bit_size, ASTContext *ast_context, QualType qual_type) +{ + uint64_t qual_type_bit_size = ast_context->getTypeSize(qual_type); + if (qual_type_bit_size == bit_size) + return true; + return false; +} + +void * +ClangASTContext::GetBuiltinTypeForEncodingAndBitSize (lldb::Encoding encoding, uint32_t bit_size) +{ + ASTContext *ast_context = getASTContext(); + + assert (ast_context != NULL); + + return GetBuiltinTypeForEncodingAndBitSize (ast_context, encoding, bit_size); +} + +void * +ClangASTContext::GetBuiltinTypeForEncodingAndBitSize (clang::ASTContext *ast_context, lldb::Encoding encoding, uint32_t bit_size) +{ + if (!ast_context) + return NULL; + + switch (encoding) + { + case lldb::eEncodingInvalid: + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->VoidPtrTy)) + return ast_context->VoidPtrTy.getAsOpaquePtr(); + break; + + case lldb::eEncodingUint: + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedCharTy)) + return ast_context->UnsignedCharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedShortTy)) + return ast_context->UnsignedShortTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedIntTy)) + return ast_context->UnsignedIntTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongTy)) + return ast_context->UnsignedLongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongLongTy)) + return ast_context->UnsignedLongLongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedInt128Ty)) + return ast_context->UnsignedInt128Ty.getAsOpaquePtr(); + break; + + case lldb::eEncodingSint: + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->CharTy)) + return ast_context->CharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->ShortTy)) + return ast_context->ShortTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->IntTy)) + return ast_context->IntTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongTy)) + return ast_context->LongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongLongTy)) + return ast_context->LongLongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->Int128Ty)) + return ast_context->Int128Ty.getAsOpaquePtr(); + break; + + case lldb::eEncodingIEEE754: + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->FloatTy)) + return ast_context->FloatTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->DoubleTy)) + return ast_context->DoubleTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongDoubleTy)) + return ast_context->LongDoubleTy.getAsOpaquePtr(); + break; + + case lldb::eEncodingVector: + default: + break; + } + + return NULL; +} + +void * +ClangASTContext::GetBuiltinTypeForDWARFEncodingAndBitSize (const char *type_name, uint32_t dw_ate, uint32_t bit_size) +{ + ASTContext *ast_context = getASTContext(); + + #define streq(a,b) strcmp(a,b) == 0 + assert (ast_context != NULL); + if (ast_context) + { + switch (dw_ate) + { + default: + break; + + case DW_ATE_address: + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->VoidPtrTy)) + return ast_context->VoidPtrTy.getAsOpaquePtr(); + break; + + case DW_ATE_boolean: + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->BoolTy)) + return ast_context->BoolTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedCharTy)) + return ast_context->UnsignedCharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedShortTy)) + return ast_context->UnsignedShortTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedIntTy)) + return ast_context->UnsignedIntTy.getAsOpaquePtr(); + break; + + case DW_ATE_complex_float: + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->FloatComplexTy)) + return ast_context->FloatComplexTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->DoubleComplexTy)) + return ast_context->DoubleComplexTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongDoubleComplexTy)) + return ast_context->LongDoubleComplexTy.getAsOpaquePtr(); + break; + + case DW_ATE_float: + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->FloatTy)) + return ast_context->FloatTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->DoubleTy)) + return ast_context->DoubleTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongDoubleTy)) + return ast_context->LongDoubleTy.getAsOpaquePtr(); + break; + + case DW_ATE_signed: + if (type_name) + { + if (streq(type_name, "int") || + streq(type_name, "signed int")) + { + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->IntTy)) + return ast_context->IntTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->Int128Ty)) + return ast_context->Int128Ty.getAsOpaquePtr(); + } + + if (streq(type_name, "long int") || + streq(type_name, "long long int") || + streq(type_name, "signed long long")) + { + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongTy)) + return ast_context->LongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongLongTy)) + return ast_context->LongLongTy.getAsOpaquePtr(); + } + + if (streq(type_name, "short") || + streq(type_name, "short int") || + streq(type_name, "signed short") || + streq(type_name, "short signed int")) + { + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->ShortTy)) + return ast_context->ShortTy.getAsOpaquePtr(); + } + + if (streq(type_name, "char") || + streq(type_name, "signed char")) + { + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->CharTy)) + return ast_context->CharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->SignedCharTy)) + return ast_context->SignedCharTy.getAsOpaquePtr(); + } + + if (streq(type_name, "wchar_t")) + { + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->WCharTy)) + return ast_context->WCharTy.getAsOpaquePtr(); + } + + } + // We weren't able to match up a type name, just search by size + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->CharTy)) + return ast_context->CharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->ShortTy)) + return ast_context->ShortTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->IntTy)) + return ast_context->IntTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongTy)) + return ast_context->LongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongLongTy)) + return ast_context->LongLongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->Int128Ty)) + return ast_context->Int128Ty.getAsOpaquePtr(); + break; + + case DW_ATE_signed_char: + if (type_name) + { + if (streq(type_name, "signed char")) + { + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->SignedCharTy)) + return ast_context->SignedCharTy.getAsOpaquePtr(); + } + } + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->CharTy)) + return ast_context->CharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->SignedCharTy)) + return ast_context->SignedCharTy.getAsOpaquePtr(); + break; + + case DW_ATE_unsigned: + if (type_name) + { + if (streq(type_name, "unsigned int")) + { + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedIntTy)) + return ast_context->UnsignedIntTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedInt128Ty)) + return ast_context->UnsignedInt128Ty.getAsOpaquePtr(); + } + + if (streq(type_name, "unsigned int") || + streq(type_name, "long unsigned int") || + streq(type_name, "unsigned long long")) + { + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongTy)) + return ast_context->UnsignedLongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongLongTy)) + return ast_context->UnsignedLongLongTy.getAsOpaquePtr(); + } + + if (streq(type_name, "unsigned short") || + streq(type_name, "short unsigned int")) + { + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedShortTy)) + return ast_context->UnsignedShortTy.getAsOpaquePtr(); + } + if (streq(type_name, "unsigned char")) + { + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedCharTy)) + return ast_context->UnsignedCharTy.getAsOpaquePtr(); + } + + } + // We weren't able to match up a type name, just search by size + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedCharTy)) + return ast_context->UnsignedCharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedShortTy)) + return ast_context->UnsignedShortTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedIntTy)) + return ast_context->UnsignedIntTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongTy)) + return ast_context->UnsignedLongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongLongTy)) + return ast_context->UnsignedLongLongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedInt128Ty)) + return ast_context->UnsignedInt128Ty.getAsOpaquePtr(); + break; + + case DW_ATE_unsigned_char: + if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedCharTy)) + return ast_context->UnsignedCharTy.getAsOpaquePtr(); + break; + + case DW_ATE_imaginary_float: + break; + } + } + // This assert should fire for anything that we don't catch above so we know + // to fix any issues we run into. + assert (!"error: ClangASTContext::GetClangTypeForDWARFEncodingAndSize() contains an unhandled encoding. Fix this ASAP!"); + return NULL; +} + +void * +ClangASTContext::GetVoidBuiltInType() +{ + return getASTContext()->VoidTy.getAsOpaquePtr(); +} + +void * +ClangASTContext::GetCStringType (bool is_const) +{ + QualType char_type(getASTContext()->CharTy); + + if (is_const) + char_type.addConst(); + + return getASTContext()->getPointerType(char_type).getAsOpaquePtr(); +} + +void * +ClangASTContext::GetVoidPtrType (bool is_const) +{ + return GetVoidPtrType(getASTContext(), is_const); +} + +void * +ClangASTContext::GetVoidPtrType (clang::ASTContext *ast_context, bool is_const) +{ + QualType void_ptr_type(ast_context->VoidPtrTy); + + if (is_const) + void_ptr_type.addConst(); + + return void_ptr_type.getAsOpaquePtr(); +} + +void * +ClangASTContext::CopyType(clang::ASTContext *dest_context, + clang::ASTContext *source_context, + void * clang_type) +{ + Diagnostic diagnostics; + FileManager file_manager; + ASTImporter importer(diagnostics, + *dest_context, file_manager, + *source_context, file_manager); + QualType ret = importer.Import(QualType::getFromOpaquePtr(clang_type)); + return ret.getAsOpaquePtr(); +} + +#pragma mark CVR modifiers + +void * +ClangASTContext::AddConstModifier (void *clang_type) +{ + if (clang_type) + { + QualType result(QualType::getFromOpaquePtr(clang_type)); + result.addConst(); + return result.getAsOpaquePtr(); + } + return NULL; +} + +void * +ClangASTContext::AddRestrictModifier (void *clang_type) +{ + if (clang_type) + { + QualType result(QualType::getFromOpaquePtr(clang_type)); + result.getQualifiers().setRestrict (true); + return result.getAsOpaquePtr(); + } + return NULL; +} + +void * +ClangASTContext::AddVolatileModifier (void *clang_type) +{ + if (clang_type) + { + QualType result(QualType::getFromOpaquePtr(clang_type)); + result.getQualifiers().setVolatile (true); + return result.getAsOpaquePtr(); + } + return NULL; +} + +#pragma mark Structure, Unions, Classes + +void * +ClangASTContext::CreateRecordType (const char *name, int kind, DeclContext *decl_ctx) +{ + ASTContext *ast_context = getASTContext(); + assert (ast_context != NULL); + + if (decl_ctx == NULL) + decl_ctx = ast_context->getTranslationUnitDecl(); + + // NOTE: Eventually CXXRecordDecl will be merged back into RecordDecl and + // we will need to update this code. I was told to currently always use + // the CXXRecordDecl class since we often don't know from debug information + // if something is struct or a class, so we default to always use the more + // complete definition just in case. + CXXRecordDecl *decl = CXXRecordDecl::Create(*ast_context, + (TagDecl::TagKind)kind, + decl_ctx, + SourceLocation(), + name && name[0] ? &ast_context->Idents.get(name) : NULL); + + return ast_context->getTagDeclType(decl).getAsOpaquePtr(); +} + +bool +ClangASTContext::AddFieldToRecordType (void * record_clang_type, const char *name, void * field_type, int access, uint32_t bitfield_bit_size) +{ + if (record_clang_type == NULL || field_type == NULL) + return false; + + ASTContext *ast_context = getASTContext(); + IdentifierTable *identifier_table = getIdentifierTable(); + + assert (ast_context != NULL); + assert (identifier_table != NULL); + + QualType record_qual_type(QualType::getFromOpaquePtr(record_clang_type)); + + Type *clang_type = record_qual_type.getTypePtr(); + if (clang_type) + { + const RecordType *record_type = dyn_cast<RecordType>(clang_type); + + if (record_type) + { + RecordDecl *record_decl = record_type->getDecl(); + + CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl); + if (cxx_record_decl) + cxx_record_decl->setEmpty (false); + + clang::Expr *bit_width = NULL; + if (bitfield_bit_size != 0) + { + APInt bitfield_bit_size_apint(ast_context->getTypeSize(ast_context->IntTy), bitfield_bit_size); + bit_width = new (*ast_context)IntegerLiteral (bitfield_bit_size_apint, ast_context->IntTy, SourceLocation()); + } + FieldDecl *field = FieldDecl::Create(*ast_context, + record_decl, + SourceLocation(), + name ? &identifier_table->get(name) : NULL, // Identifier + QualType::getFromOpaquePtr(field_type), // Field type + NULL, // DeclaratorInfo * + bit_width, // BitWidth + false); // Mutable + + field->setAccess((AccessSpecifier)access); + + if (field) + { + record_decl->addDecl(field); + return true; + } + } + } + return false; +} + +bool +ClangASTContext::FieldIsBitfield (FieldDecl* field, uint32_t& bitfield_bit_size) +{ + return FieldIsBitfield(getASTContext(), field, bitfield_bit_size); +} + +bool +ClangASTContext::FieldIsBitfield +( + ASTContext *ast_context, + FieldDecl* field, + uint32_t& bitfield_bit_size +) +{ + if (ast_context == NULL || field == NULL) + return false; + + if (field->isBitField()) + { + Expr* bit_width_expr = field->getBitWidth(); + if (bit_width_expr) + { + llvm::APSInt bit_width_apsint; + if (bit_width_expr->isIntegerConstantExpr(bit_width_apsint, *ast_context)) + { + bitfield_bit_size = bit_width_apsint.getLimitedValue(UINT32_MAX); + return true; + } + } + } + return false; +} + +bool +ClangASTContext::RecordHasFields (const RecordDecl *record_decl) +{ + if (record_decl == NULL) + return false; + + if (!record_decl->field_empty()) + return true; + + // No fields, lets check this is a CXX record and check the base classes + const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl); + if (cxx_record_decl) + { + CXXRecordDecl::base_class_const_iterator base_class, base_class_end; + for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end(); + base_class != base_class_end; + ++base_class) + { + const CXXRecordDecl *base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl()); + if (RecordHasFields(base_class_decl)) + return true; + } + } + return false; +} + +void +ClangASTContext::SetDefaultAccessForRecordFields (void *clang_qual_type, int default_accessibility, int *assigned_accessibilities, size_t num_assigned_accessibilities) +{ + if (clang_qual_type) + { + QualType qual_type(QualType::getFromOpaquePtr(clang_qual_type)); + Type *clang_type = qual_type.getTypePtr(); + if (clang_type) + { + RecordType *record_type = dyn_cast<RecordType>(clang_type); + if (record_type) + { + RecordDecl *record_decl = record_type->getDecl(); + if (record_decl) + { + uint32_t field_idx; + RecordDecl::field_iterator field, field_end; + for (field = record_decl->field_begin(), field_end = record_decl->field_end(), field_idx = 0; + field != field_end; + ++field, ++field_idx) + { + // If no accessibility was assigned, assign the correct one + if (field_idx < num_assigned_accessibilities && assigned_accessibilities[field_idx] == clang::AS_none) + field->setAccess ((AccessSpecifier)default_accessibility); + } + } + } + } + } +} + +#pragma mark C++ Base Classes + +CXXBaseSpecifier * +ClangASTContext::CreateBaseClassSpecifier (void *base_class_type, int access, bool is_virtual, bool base_of_class) +{ + if (base_class_type) + return new CXXBaseSpecifier(SourceRange(), is_virtual, base_of_class, (AccessSpecifier)access, QualType::getFromOpaquePtr(base_class_type)); + return NULL; +} + +bool +ClangASTContext::SetBaseClassesForClassType (void *class_clang_type, CXXBaseSpecifier const * const *base_classes, unsigned num_base_classes) +{ + if (class_clang_type) + { + ASTContext *ast_context = getASTContext(); + IdentifierTable *identifier_table = getIdentifierTable(); + + assert (ast_context != NULL); + assert (identifier_table != NULL); + + Type *clang_type = QualType::getFromOpaquePtr(class_clang_type).getTypePtr(); + if (clang_type) + { + RecordType *record_type = dyn_cast<RecordType>(clang_type); + if (record_type) + { + CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_type->getDecl()); + if (cxx_record_decl) + { + //cxx_record_decl->setEmpty (false); + cxx_record_decl->setBases(base_classes, num_base_classes); + return true; + } + } + } + } + return false; +} + + +#pragma mark Aggregate Types + +bool +ClangASTContext::IsAggregateType (void *clang_type) +{ + if (clang_type == NULL) + return false; + + QualType qual_type (QualType::getFromOpaquePtr(clang_type)); + + if (qual_type->isAggregateType ()) + return true; + + switch (qual_type->getTypeClass()) + { + case Type::IncompleteArray: + case Type::VariableArray: + case Type::ConstantArray: + case Type::ExtVector: + case Type::Vector: + case Type::Record: + return true; + + case Type::Typedef: + return ClangASTContext::IsAggregateType (cast<TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr()); + + default: + break; + } + // The clang type does have a value + return false; +} + +uint32_t +ClangASTContext::GetNumChildren (void *clang_qual_type, bool omit_empty_base_classes) +{ + if (clang_qual_type == NULL) + return 0; + + uint32_t num_children = 0; + QualType qual_type(QualType::getFromOpaquePtr(clang_qual_type)); + switch (qual_type->getTypeClass()) + { + case Type::Record: + { + const RecordType *record_type = cast<RecordType>(qual_type.getTypePtr()); + const RecordDecl *record_decl = record_type->getDecl(); + assert(record_decl); + const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl); + if (cxx_record_decl) + { + if (omit_empty_base_classes) + { + // Check each base classes to see if it or any of its + // base classes contain any fields. This can help + // limit the noise in variable views by not having to + // show base classes that contain no members. + CXXRecordDecl::base_class_const_iterator base_class, base_class_end; + for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end(); + base_class != base_class_end; + ++base_class) + { + const CXXRecordDecl *base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl()); + + // Skip empty base classes + if (RecordHasFields(base_class_decl) == false) + continue; + + num_children++; + } + } + else + { + // Include all base classes + num_children += cxx_record_decl->getNumBases(); + } + + } + RecordDecl::field_iterator field, field_end; + for (field = record_decl->field_begin(), field_end = record_decl->field_end(); field != field_end; ++field) + ++num_children; + } + break; + + case Type::ConstantArray: + num_children = cast<ConstantArrayType>(qual_type.getTypePtr())->getSize().getLimitedValue(); + break; + + case Type::Pointer: + { + PointerType *pointer_type = cast<PointerType>(qual_type.getTypePtr()); + QualType pointee_type = pointer_type->getPointeeType(); + uint32_t num_pointee_children = ClangASTContext::GetNumChildren (pointee_type.getAsOpaquePtr(), omit_empty_base_classes); + // If this type points to a simple type, then it has 1 child + if (num_pointee_children == 0) + num_children = 1; + else + num_children = num_pointee_children; + } + break; + + case Type::Typedef: + num_children = ClangASTContext::GetNumChildren (cast<TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr(), omit_empty_base_classes); + break; + + default: + break; + } + return num_children; +} + + +void * +ClangASTContext::GetChildClangTypeAtIndex +( + const char *parent_name, + void *parent_clang_type, + uint32_t idx, + bool transparent_pointers, + bool omit_empty_base_classes, + std::string& child_name, + uint32_t &child_byte_size, + int32_t &child_byte_offset, + uint32_t &child_bitfield_bit_size, + uint32_t &child_bitfield_bit_offset +) +{ + if (parent_clang_type) + + return GetChildClangTypeAtIndex (getASTContext(), + parent_name, + parent_clang_type, + idx, + transparent_pointers, + omit_empty_base_classes, + child_name, + child_byte_size, + child_byte_offset, + child_bitfield_bit_size, + child_bitfield_bit_offset); + return NULL; +} + +void * +ClangASTContext::GetChildClangTypeAtIndex +( + ASTContext *ast_context, + const char *parent_name, + void *parent_clang_type, + uint32_t idx, + bool transparent_pointers, + bool omit_empty_base_classes, + std::string& child_name, + uint32_t &child_byte_size, + int32_t &child_byte_offset, + uint32_t &child_bitfield_bit_size, + uint32_t &child_bitfield_bit_offset +) +{ + if (parent_clang_type == NULL) + return NULL; + + if (idx < ClangASTContext::GetNumChildren (parent_clang_type, omit_empty_base_classes)) + { + uint32_t bit_offset; + child_bitfield_bit_size = 0; + child_bitfield_bit_offset = 0; + QualType parent_qual_type(QualType::getFromOpaquePtr(parent_clang_type)); + switch (parent_qual_type->getTypeClass()) + { + case Type::Record: + { + const RecordType *record_type = cast<RecordType>(parent_qual_type.getTypePtr()); + const RecordDecl *record_decl = record_type->getDecl(); + assert(record_decl); + const ASTRecordLayout &record_layout = ast_context->getASTRecordLayout(record_decl); + uint32_t child_idx = 0; + + const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl); + if (cxx_record_decl) + { + // We might have base classes to print out first + CXXRecordDecl::base_class_const_iterator base_class, base_class_end; + for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end(); + base_class != base_class_end; + ++base_class) + { + const CXXRecordDecl *base_class_decl = NULL; + + // Skip empty base classes + if (omit_empty_base_classes) + { + base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl()); + if (RecordHasFields(base_class_decl) == false) + continue; + } + + if (idx == child_idx) + { + if (base_class_decl == NULL) + base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl()); + + + if (base_class->isVirtual()) + bit_offset = record_layout.getVBaseClassOffset(base_class_decl); + else + bit_offset = record_layout.getBaseClassOffset(base_class_decl); + + // Base classes should be a multiple of 8 bits in size + assert (bit_offset % 8 == 0); + child_byte_offset = bit_offset/8; + std::string base_class_type_name(base_class->getType().getAsString()); + + child_name.assign(base_class_type_name.c_str()); + + uint64_t clang_type_info_bit_size = ast_context->getTypeSize(base_class->getType()); + + // Base classes biut sizes should be a multiple of 8 bits in size + assert (clang_type_info_bit_size % 8 == 0); + child_byte_size = clang_type_info_bit_size / 8; + return base_class->getType().getAsOpaquePtr(); + } + // We don't increment the child index in the for loop since we might + // be skipping empty base classes + ++child_idx; + } + } + const unsigned num_fields = record_layout.getFieldCount(); + + // Make sure index is in range... + uint32_t field_idx = 0; + RecordDecl::field_iterator field, field_end; + for (field = record_decl->field_begin(), field_end = record_decl->field_end(); field != field_end; ++field, ++field_idx, ++child_idx) + { + if (idx == child_idx) + { + // Print the member type if requested + // Print the member name and equal sign + child_name.assign(field->getNameAsString().c_str()); + + // Figure out the type byte size (field_type_info.first) and + // alignment (field_type_info.second) from the AST context. + std::pair<uint64_t, unsigned> field_type_info = ast_context->getTypeInfo(field->getType()); + assert(field_idx < num_fields); + + child_byte_size = field_type_info.first / 8; + + // Figure out the field offset within the current struct/union/class type + bit_offset = record_layout.getFieldOffset (field_idx); + child_byte_offset = bit_offset / 8; + if (ClangASTContext::FieldIsBitfield (ast_context, *field, child_bitfield_bit_size)) + child_bitfield_bit_offset = bit_offset % 8; + + return field->getType().getAsOpaquePtr(); + } + } + } + break; + + case Type::ConstantArray: + { + const ConstantArrayType *array = cast<ConstantArrayType>(parent_qual_type.getTypePtr()); + const uint64_t element_count = array->getSize().getLimitedValue(); + + if (idx < element_count) + { + std::pair<uint64_t, unsigned> field_type_info = ast_context->getTypeInfo(array->getElementType()); + + char element_name[32]; + ::snprintf (element_name, sizeof (element_name), "%s[%u]", parent_name ? parent_name : "", idx); + + child_name.assign(element_name); + assert(field_type_info.first % 8 == 0); + child_byte_size = field_type_info.first / 8; + child_byte_offset = idx * child_byte_size; + return array->getElementType().getAsOpaquePtr(); + } + } + break; + + case Type::Pointer: + { + PointerType *pointer_type = cast<PointerType>(parent_qual_type.getTypePtr()); + QualType pointee_type = pointer_type->getPointeeType(); + + if (transparent_pointers && ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) + { + return GetChildClangTypeAtIndex (ast_context, + parent_name, + pointer_type->getPointeeType().getAsOpaquePtr(), + idx, + transparent_pointers, + omit_empty_base_classes, + child_name, + child_byte_size, + child_byte_offset, + child_bitfield_bit_size, + child_bitfield_bit_offset); + } + else + { + if (parent_name) + { + child_name.assign(1, '*'); + child_name += parent_name; + } + + // We have a pointer to an simple type + if (idx == 0) + { + std::pair<uint64_t, unsigned> clang_type_info = ast_context->getTypeInfo(pointee_type); + assert(clang_type_info.first % 8 == 0); + child_byte_size = clang_type_info.first / 8; + child_byte_offset = 0; + return pointee_type.getAsOpaquePtr(); + } + } + } + break; + + case Type::Typedef: + return GetChildClangTypeAtIndex (ast_context, + parent_name, + cast<TypedefType>(parent_qual_type)->LookThroughTypedefs().getAsOpaquePtr(), + idx, + transparent_pointers, + omit_empty_base_classes, + child_name, + child_byte_size, + child_byte_offset, + child_bitfield_bit_size, + child_bitfield_bit_offset); + break; + + default: + break; + } + } + return false; +} + +static inline bool +BaseSpecifierIsEmpty (const CXXBaseSpecifier *b) +{ + return ClangASTContext::RecordHasFields(cast<CXXRecordDecl>(b->getType()->getAs<RecordType>()->getDecl())) == false; +} + +static uint32_t +GetNumBaseClasses (const CXXRecordDecl *cxx_record_decl, bool omit_empty_base_classes) +{ + uint32_t num_bases = 0; + if (cxx_record_decl) + { + if (omit_empty_base_classes) + { + CXXRecordDecl::base_class_const_iterator base_class, base_class_end; + for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end(); + base_class != base_class_end; + ++base_class) + { + // Skip empty base classes + if (omit_empty_base_classes) + { + if (BaseSpecifierIsEmpty (base_class)) + continue; + } + ++num_bases; + } + } + else + num_bases = cxx_record_decl->getNumBases(); + } + return num_bases; +} + + +static uint32_t +GetIndexForRecordBase +( + const RecordDecl *record_decl, + const CXXBaseSpecifier *base_spec, + bool omit_empty_base_classes +) +{ + uint32_t child_idx = 0; + + const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl); + +// const char *super_name = record_decl->getNameAsCString(); +// const char *base_name = base_spec->getType()->getAs<RecordType>()->getDecl()->getNameAsCString(); +// printf ("GetIndexForRecordChild (%s, %s)\n", super_name, base_name); +// + if (cxx_record_decl) + { + CXXRecordDecl::base_class_const_iterator base_class, base_class_end; + for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end(); + base_class != base_class_end; + ++base_class) + { + if (omit_empty_base_classes) + { + if (BaseSpecifierIsEmpty (base_class)) + continue; + } + +// printf ("GetIndexForRecordChild (%s, %s) base[%u] = %s\n", super_name, base_name, +// child_idx, +// base_class->getType()->getAs<RecordType>()->getDecl()->getNameAsCString()); +// +// + if (base_class == base_spec) + return child_idx; + ++child_idx; + } + } + + return UINT32_MAX; +} + + +static uint32_t +GetIndexForRecordChild +( + const RecordDecl *record_decl, + NamedDecl *canonical_decl, + bool omit_empty_base_classes +) +{ + uint32_t child_idx = GetNumBaseClasses (dyn_cast<CXXRecordDecl>(record_decl), omit_empty_base_classes); + +// const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl); +// +//// printf ("GetIndexForRecordChild (%s, %s)\n", record_decl->getNameAsCString(), canonical_decl->getNameAsCString()); +// if (cxx_record_decl) +// { +// CXXRecordDecl::base_class_const_iterator base_class, base_class_end; +// for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end(); +// base_class != base_class_end; +// ++base_class) +// { +// if (omit_empty_base_classes) +// { +// if (BaseSpecifierIsEmpty (base_class)) +// continue; +// } +// +//// printf ("GetIndexForRecordChild (%s, %s) base[%u] = %s\n", +//// record_decl->getNameAsCString(), +//// canonical_decl->getNameAsCString(), +//// child_idx, +//// base_class->getType()->getAs<RecordType>()->getDecl()->getNameAsCString()); +// +// +// CXXRecordDecl *curr_base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl()); +// if (curr_base_class_decl == canonical_decl) +// { +// return child_idx; +// } +// ++child_idx; +// } +// } +// +// const uint32_t num_bases = child_idx; + RecordDecl::field_iterator field, field_end; + for (field = record_decl->field_begin(), field_end = record_decl->field_end(); + field != field_end; + ++field, ++child_idx) + { +// printf ("GetIndexForRecordChild (%s, %s) field[%u] = %s\n", +// record_decl->getNameAsCString(), +// canonical_decl->getNameAsCString(), +// child_idx - num_bases, +// field->getNameAsCString()); + + if (field->getCanonicalDecl() == canonical_decl) + return child_idx; + } + + return UINT32_MAX; +} + +// Look for a child member (doesn't include base classes, but it does include +// their members) in the type hierarchy. Returns an index path into "clang_type" +// on how to reach the appropriate member. +// +// class A +// { +// public: +// int m_a; +// int m_b; +// }; +// +// class B +// { +// }; +// +// class C : +// public B, +// public A +// { +// }; +// +// If we have a clang type that describes "class C", and we wanted to looked +// "m_b" in it: +// +// With omit_empty_base_classes == false we would get an integer array back with: +// { 1, 1 } +// The first index 1 is the child index for "class A" within class C +// The second index 1 is the child index for "m_b" within class A +// +// With omit_empty_base_classes == true we would get an integer array back with: +// { 0, 1 } +// The first index 0 is the child index for "class A" within class C (since class B doesn't have any members it doesn't count) +// The second index 1 is the child index for "m_b" within class A + +size_t +ClangASTContext::GetIndexOfChildMemberWithName +( + ASTContext *ast_context, + void *clang_type, + const char *name, + bool omit_empty_base_classes, + std::vector<uint32_t>& child_indexes +) +{ + if (clang_type && name && name[0]) + { + QualType qual_type(QualType::getFromOpaquePtr(clang_type)); + switch (qual_type->getTypeClass()) + { + case Type::Record: + { + const RecordType *record_type = cast<RecordType>(qual_type.getTypePtr()); + const RecordDecl *record_decl = record_type->getDecl(); + + assert(record_decl); + uint32_t child_idx = 0; + + const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl); + + // Try and find a field that matches NAME + RecordDecl::field_iterator field, field_end; + StringRef name_sref(name); + for (field = record_decl->field_begin(), field_end = record_decl->field_end(); + field != field_end; + ++field, ++child_idx) + { + if (field->getName().equals (name_sref)) + { + // We have to add on the number of base classes to this index! + child_indexes.push_back (child_idx + GetNumBaseClasses (cxx_record_decl, omit_empty_base_classes)); + return child_indexes.size(); + } + } + + if (cxx_record_decl) + { + const RecordDecl *parent_record_decl = cxx_record_decl; + + //printf ("parent = %s\n", parent_record_decl->getNameAsCString()); + + //const Decl *root_cdecl = cxx_record_decl->getCanonicalDecl(); + // Didn't find things easily, lets let clang do its thang... + IdentifierInfo & ident_ref = ast_context->Idents.get(name, name + strlen (name)); + DeclarationName decl_name(&ident_ref); + + CXXBasePaths paths; + if (cxx_record_decl->lookupInBases(CXXRecordDecl::FindOrdinaryMember, + decl_name.getAsOpaquePtr(), + paths)) + { + uint32_t child_idx; + CXXBasePaths::const_paths_iterator path, path_end = paths.end(); + for (path = paths.begin(); path != path_end; ++path) + { + const size_t num_path_elements = path->size(); + for (size_t e=0; e<num_path_elements; ++e) + { + CXXBasePathElement elem = (*path)[e]; + + child_idx = GetIndexForRecordBase (parent_record_decl, elem.Base, omit_empty_base_classes); + if (child_idx == UINT32_MAX) + { + child_indexes.clear(); + return 0; + } + else + { + child_indexes.push_back (child_idx); + parent_record_decl = cast<RecordDecl>(elem.Base->getType()->getAs<RecordType>()->getDecl()); + } + } + DeclContext::lookup_iterator named_decl_pos; + for (named_decl_pos = path->Decls.first; + named_decl_pos != path->Decls.second && parent_record_decl; + ++named_decl_pos) + { + //printf ("path[%zu] = %s\n", child_indexes.size(), (*named_decl_pos)->getNameAsCString()); + + child_idx = GetIndexForRecordChild (parent_record_decl, *named_decl_pos, omit_empty_base_classes); + if (child_idx == UINT32_MAX) + { + child_indexes.clear(); + return 0; + } + else + { + child_indexes.push_back (child_idx); + } + } + } + return child_indexes.size(); + } + } + + } + break; + + case Type::ConstantArray: + { +// const ConstantArrayType *array = cast<ConstantArrayType>(parent_qual_type.getTypePtr()); +// const uint64_t element_count = array->getSize().getLimitedValue(); +// +// if (idx < element_count) +// { +// std::pair<uint64_t, unsigned> field_type_info = ast_context->getTypeInfo(array->getElementType()); +// +// char element_name[32]; +// ::snprintf (element_name, sizeof (element_name), "%s[%u]", parent_name ? parent_name : "", idx); +// +// child_name.assign(element_name); +// assert(field_type_info.first % 8 == 0); +// child_byte_size = field_type_info.first / 8; +// child_byte_offset = idx * child_byte_size; +// return array->getElementType().getAsOpaquePtr(); +// } + } + break; + +// case Type::MemberPointerType: +// { +// MemberPointerType *mem_ptr_type = cast<MemberPointerType>(qual_type.getTypePtr()); +// QualType pointee_type = mem_ptr_type->getPointeeType(); +// +// if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) +// { +// return GetIndexOfChildWithName (ast_context, +// mem_ptr_type->getPointeeType().getAsOpaquePtr(), +// name); +// } +// } +// break; +// + case Type::LValueReference: + case Type::RValueReference: + { + ReferenceType *reference_type = cast<ReferenceType>(qual_type.getTypePtr()); + QualType pointee_type = reference_type->getPointeeType(); + + if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) + { + return GetIndexOfChildMemberWithName (ast_context, + reference_type->getPointeeType().getAsOpaquePtr(), + name, + omit_empty_base_classes, + child_indexes); + } + } + break; + + case Type::Pointer: + { + PointerType *pointer_type = cast<PointerType>(qual_type.getTypePtr()); + QualType pointee_type = pointer_type->getPointeeType(); + + if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) + { + return GetIndexOfChildMemberWithName (ast_context, + pointer_type->getPointeeType().getAsOpaquePtr(), + name, + omit_empty_base_classes, + child_indexes); + } + else + { +// if (parent_name) +// { +// child_name.assign(1, '*'); +// child_name += parent_name; +// } +// +// // We have a pointer to an simple type +// if (idx == 0) +// { +// std::pair<uint64_t, unsigned> clang_type_info = ast_context->getTypeInfo(pointee_type); +// assert(clang_type_info.first % 8 == 0); +// child_byte_size = clang_type_info.first / 8; +// child_byte_offset = 0; +// return pointee_type.getAsOpaquePtr(); +// } + } + } + break; + + case Type::Typedef: + return GetIndexOfChildMemberWithName (ast_context, + cast<TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr(), + name, + omit_empty_base_classes, + child_indexes); + + default: + break; + } + } + return 0; +} + + +// Get the index of the child of "clang_type" whose name matches. This function +// doesn't descend into the children, but only looks one level deep and name +// matches can include base class names. + +uint32_t +ClangASTContext::GetIndexOfChildWithName +( + ASTContext *ast_context, + void *clang_type, + const char *name, + bool omit_empty_base_classes +) +{ + if (clang_type && name && name[0]) + { + QualType qual_type(QualType::getFromOpaquePtr(clang_type)); + switch (qual_type->getTypeClass()) + { + case Type::Record: + { + const RecordType *record_type = cast<RecordType>(qual_type.getTypePtr()); + const RecordDecl *record_decl = record_type->getDecl(); + + assert(record_decl); + uint32_t child_idx = 0; + + const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl); + + if (cxx_record_decl) + { + CXXRecordDecl::base_class_const_iterator base_class, base_class_end; + for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end(); + base_class != base_class_end; + ++base_class) + { + // Skip empty base classes + CXXRecordDecl *base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl()); + if (omit_empty_base_classes && RecordHasFields(base_class_decl) == false) + continue; + + if (base_class->getType().getAsString().compare (name) == 0) + return child_idx; + ++child_idx; + } + } + + // Try and find a field that matches NAME + RecordDecl::field_iterator field, field_end; + StringRef name_sref(name); + for (field = record_decl->field_begin(), field_end = record_decl->field_end(); + field != field_end; + ++field, ++child_idx) + { + if (field->getName().equals (name_sref)) + return child_idx; + } + + } + break; + + case Type::ConstantArray: + { +// const ConstantArrayType *array = cast<ConstantArrayType>(parent_qual_type.getTypePtr()); +// const uint64_t element_count = array->getSize().getLimitedValue(); +// +// if (idx < element_count) +// { +// std::pair<uint64_t, unsigned> field_type_info = ast_context->getTypeInfo(array->getElementType()); +// +// char element_name[32]; +// ::snprintf (element_name, sizeof (element_name), "%s[%u]", parent_name ? parent_name : "", idx); +// +// child_name.assign(element_name); +// assert(field_type_info.first % 8 == 0); +// child_byte_size = field_type_info.first / 8; +// child_byte_offset = idx * child_byte_size; +// return array->getElementType().getAsOpaquePtr(); +// } + } + break; + +// case Type::MemberPointerType: +// { +// MemberPointerType *mem_ptr_type = cast<MemberPointerType>(qual_type.getTypePtr()); +// QualType pointee_type = mem_ptr_type->getPointeeType(); +// +// if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) +// { +// return GetIndexOfChildWithName (ast_context, +// mem_ptr_type->getPointeeType().getAsOpaquePtr(), +// name); +// } +// } +// break; +// + case Type::LValueReference: + case Type::RValueReference: + { + ReferenceType *reference_type = cast<ReferenceType>(qual_type.getTypePtr()); + QualType pointee_type = reference_type->getPointeeType(); + + if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) + { + return GetIndexOfChildWithName (ast_context, + reference_type->getPointeeType().getAsOpaquePtr(), + name, + omit_empty_base_classes); + } + } + break; + + case Type::Pointer: + { + PointerType *pointer_type = cast<PointerType>(qual_type.getTypePtr()); + QualType pointee_type = pointer_type->getPointeeType(); + + if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) + { + return GetIndexOfChildWithName (ast_context, + pointer_type->getPointeeType().getAsOpaquePtr(), + name, + omit_empty_base_classes); + } + else + { +// if (parent_name) +// { +// child_name.assign(1, '*'); +// child_name += parent_name; +// } +// +// // We have a pointer to an simple type +// if (idx == 0) +// { +// std::pair<uint64_t, unsigned> clang_type_info = ast_context->getTypeInfo(pointee_type); +// assert(clang_type_info.first % 8 == 0); +// child_byte_size = clang_type_info.first / 8; +// child_byte_offset = 0; +// return pointee_type.getAsOpaquePtr(); +// } + } + } + break; + + case Type::Typedef: + return GetIndexOfChildWithName (ast_context, + cast<TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr(), + name, + omit_empty_base_classes); + + default: + break; + } + } + return UINT32_MAX; +} + +#pragma mark TagType + +bool +ClangASTContext::SetTagTypeKind (void *tag_clang_type, int kind) +{ + if (tag_clang_type) + { + QualType tag_qual_type(QualType::getFromOpaquePtr(tag_clang_type)); + Type *clang_type = tag_qual_type.getTypePtr(); + if (clang_type) + { + TagType *tag_type = dyn_cast<TagType>(clang_type); + if (tag_type) + { + TagDecl *tag_decl = dyn_cast<TagDecl>(tag_type->getDecl()); + if (tag_decl) + { + tag_decl->setTagKind ((TagDecl::TagKind)kind); + return true; + } + } + } + } + return false; +} + + +#pragma mark DeclContext Functions + +DeclContext * +ClangASTContext::GetDeclContextForType (void *clang_type) +{ + if (clang_type == NULL) + return NULL; + + QualType qual_type(QualType::getFromOpaquePtr(clang_type)); + switch (qual_type->getTypeClass()) + { + case Type::FunctionNoProto: break; + case Type::FunctionProto: break; + case Type::IncompleteArray: break; + case Type::VariableArray: break; + case Type::ConstantArray: break; + case Type::ExtVector: break; + case Type::Vector: break; + case Type::Builtin: break; + case Type::ObjCObjectPointer: break; + case Type::BlockPointer: break; + case Type::Pointer: break; + case Type::LValueReference: break; + case Type::RValueReference: break; + case Type::MemberPointer: break; + case Type::Complex: break; + case Type::ObjCInterface: break; + case Type::Record: + return cast<RecordType>(qual_type)->getDecl(); + case Type::Enum: + return cast<EnumType>(qual_type)->getDecl(); + case Type::Typedef: + return ClangASTContext::GetDeclContextForType (cast<TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr()); + + case Type::TypeOfExpr: break; + case Type::TypeOf: break; + case Type::Decltype: break; + //case Type::QualifiedName: break; + case Type::TemplateSpecialization: break; + } + // No DeclContext in this type... + return NULL; +} + +#pragma mark Namespace Declarations + +NamespaceDecl * +ClangASTContext::GetUniqueNamespaceDeclaration (const char *name, const Declaration &decl, DeclContext *decl_ctx) +{ + // TODO: Do something intelligent with the Declaration object passed in + // like maybe filling in the SourceLocation with it... + if (name) + { + ASTContext *ast_context = getASTContext(); + if (decl_ctx == NULL) + decl_ctx = ast_context->getTranslationUnitDecl(); + return NamespaceDecl::Create(*ast_context, decl_ctx, SourceLocation(), &ast_context->Idents.get(name)); + } + return NULL; +} + + +#pragma mark Function Types + +FunctionDecl * +ClangASTContext::CreateFunctionDeclaration (const char *name, void *function_clang_type, int storage, bool is_inline) +{ + if (name) + { + ASTContext *ast_context = getASTContext(); + assert (ast_context != NULL); + + if (name && name[0]) + { + return FunctionDecl::Create(*ast_context, + ast_context->getTranslationUnitDecl(), + SourceLocation(), + DeclarationName (&ast_context->Idents.get(name)), + QualType::getFromOpaquePtr(function_clang_type), + NULL, + (FunctionDecl::StorageClass)storage, + (FunctionDecl::StorageClass)storage, + is_inline); + } + else + { + return FunctionDecl::Create(*ast_context, + ast_context->getTranslationUnitDecl(), + SourceLocation(), + DeclarationName (), + QualType::getFromOpaquePtr(function_clang_type), + NULL, + (FunctionDecl::StorageClass)storage, + (FunctionDecl::StorageClass)storage, + is_inline); + } + } + return NULL; +} + +void * +ClangASTContext::CreateFunctionType (void *result_type, void **args, unsigned num_args, bool isVariadic, unsigned TypeQuals) +{ + ASTContext *ast_context = getASTContext(); + assert (ast_context != NULL); + std::vector<QualType> qual_type_args; + for (unsigned i=0; i<num_args; ++i) + qual_type_args.push_back (QualType::getFromOpaquePtr(args[i])); + + // TODO: Detect calling convention in DWARF? + return ast_context->getFunctionType(QualType::getFromOpaquePtr(result_type), + qual_type_args.data(), + qual_type_args.size(), + isVariadic, + TypeQuals, + false, // hasExceptionSpec + false, // hasAnyExceptionSpec, + 0, // NumExs + 0, // const QualType *ExArray + FunctionType::ExtInfo ()).getAsOpaquePtr(); // NoReturn); +} + +ParmVarDecl * +ClangASTContext::CreateParmeterDeclaration (const char *name, void * return_type, int storage) +{ + ASTContext *ast_context = getASTContext(); + assert (ast_context != NULL); + return ParmVarDecl::Create(*ast_context, + ast_context->getTranslationUnitDecl(), + SourceLocation(), + name && name[0] ? &ast_context->Idents.get(name) : NULL, + QualType::getFromOpaquePtr(return_type), + NULL, + (VarDecl::StorageClass)storage, + (VarDecl::StorageClass)storage, + 0); +} + +void +ClangASTContext::SetFunctionParameters (FunctionDecl *function_decl, ParmVarDecl **params, unsigned num_params) +{ + if (function_decl) + function_decl->setParams (params, num_params); +} + + +#pragma mark Array Types + +void * +ClangASTContext::CreateArrayType (void *element_type, size_t element_count, uint32_t bit_stride) +{ + if (element_type) + { + ASTContext *ast_context = getASTContext(); + assert (ast_context != NULL); + llvm::APInt ap_element_count (64, element_count); + return ast_context->getConstantArrayType(QualType::getFromOpaquePtr(element_type), + ap_element_count, + ArrayType::Normal, + 0).getAsOpaquePtr(); // ElemQuals + } + return NULL; +} + + +#pragma mark TagDecl + +bool +ClangASTContext::StartTagDeclarationDefinition (void *clang_type) +{ + if (clang_type) + { + QualType qual_type (QualType::getFromOpaquePtr(clang_type)); + Type *t = qual_type.getTypePtr(); + if (t) + { + TagType *tag_type = dyn_cast<TagType>(t); + if (tag_type) + { + TagDecl *tag_decl = tag_type->getDecl(); + if (tag_decl) + { + tag_decl->startDefinition(); + return true; + } + } + } + } + return false; +} + +bool +ClangASTContext::CompleteTagDeclarationDefinition (void *clang_type) +{ + if (clang_type) + { + QualType qual_type (QualType::getFromOpaquePtr(clang_type)); + Type *t = qual_type.getTypePtr(); + if (t) + { + TagType *tag_type = dyn_cast<TagType>(t); + if (tag_type) + { + TagDecl *tag_decl = tag_type->getDecl(); + if (tag_decl) + { + tag_decl->completeDefinition(); + return true; + } + } + } + } + return false; +} + + +#pragma mark Enumeration Types + +void * +ClangASTContext::CreateEnumerationType (const Declaration &decl, const char *name) +{ + // TODO: Do something intelligent with the Declaration object passed in + // like maybe filling in the SourceLocation with it... + ASTContext *ast_context = getASTContext(); + assert (ast_context != NULL); + EnumDecl *enum_decl = EnumDecl::Create(*ast_context, + ast_context->getTranslationUnitDecl(), + SourceLocation(), + name && name[0] ? &ast_context->Idents.get(name) : NULL, + SourceLocation(), + NULL); + if (enum_decl) + return ast_context->getTagDeclType(enum_decl).getAsOpaquePtr(); + return NULL; +} + +bool +ClangASTContext::AddEnumerationValueToEnumerationType +( + void *enum_clang_type, + void *enumerator_clang_type, + const Declaration &decl, + const char *name, + int64_t enum_value, + uint32_t enum_value_bit_size +) +{ + if (enum_clang_type && enumerator_clang_type && name) + { + // TODO: Do something intelligent with the Declaration object passed in + // like maybe filling in the SourceLocation with it... + ASTContext *ast_context = getASTContext(); + IdentifierTable *identifier_table = getIdentifierTable(); + + assert (ast_context != NULL); + assert (identifier_table != NULL); + QualType enum_qual_type (QualType::getFromOpaquePtr(enum_clang_type)); + + Type *clang_type = enum_qual_type.getTypePtr(); + if (clang_type) + { + const EnumType *enum_type = dyn_cast<EnumType>(clang_type); + + if (enum_type) + { + llvm::APSInt enum_llvm_apsint(enum_value_bit_size, false); + enum_llvm_apsint = enum_value; + EnumConstantDecl *enumerator_decl = + EnumConstantDecl::Create(*ast_context, + enum_type->getDecl(), + SourceLocation(), + name ? &identifier_table->get(name) : NULL, // Identifier + QualType::getFromOpaquePtr(enumerator_clang_type), + NULL, + enum_llvm_apsint); + + if (enumerator_decl) + { + enum_type->getDecl()->addDecl(enumerator_decl); + return true; + } + } + } + } + return false; +} + +#pragma mark Pointers & References + +void * +ClangASTContext::CreatePointerType (void *clang_type) +{ + if (clang_type) + return getASTContext()->getPointerType(QualType::getFromOpaquePtr(clang_type)).getAsOpaquePtr(); + return NULL; +} + +void * +ClangASTContext::CreateLValueReferenceType (void *clang_type) +{ + if (clang_type) + return getASTContext()->getLValueReferenceType (QualType::getFromOpaquePtr(clang_type)).getAsOpaquePtr(); + return NULL; +} + +void * +ClangASTContext::CreateRValueReferenceType (void *clang_type) +{ + if (clang_type) + return getASTContext()->getRValueReferenceType (QualType::getFromOpaquePtr(clang_type)).getAsOpaquePtr(); + return NULL; +} + +size_t +ClangASTContext::GetPointerBitSize () +{ + ASTContext *ast_context = getASTContext(); + return ast_context->getTypeSize(ast_context->VoidPtrTy); +} + +bool +ClangASTContext::IsPointerOrReferenceType (void *clang_type, void **target_type) +{ + if (clang_type == NULL) + return false; + + QualType qual_type (QualType::getFromOpaquePtr(clang_type)); + switch (qual_type->getTypeClass()) + { + case Type::ObjCObjectPointer: + if (target_type) + *target_type = cast<ObjCObjectPointerType>(qual_type)->getPointeeType().getAsOpaquePtr(); + return true; + case Type::BlockPointer: + if (target_type) + *target_type = cast<BlockPointerType>(qual_type)->getPointeeType().getAsOpaquePtr(); + return true; + case Type::Pointer: + if (target_type) + *target_type = cast<PointerType>(qual_type)->getPointeeType().getAsOpaquePtr(); + return true; + case Type::MemberPointer: + if (target_type) + *target_type = cast<MemberPointerType>(qual_type)->getPointeeType().getAsOpaquePtr(); + return true; + case Type::LValueReference: + if (target_type) + *target_type = cast<LValueReferenceType>(qual_type)->desugar().getAsOpaquePtr(); + return true; + case Type::RValueReference: + if (target_type) + *target_type = cast<LValueReferenceType>(qual_type)->desugar().getAsOpaquePtr(); + return true; + case Type::Typedef: + return ClangASTContext::IsPointerOrReferenceType (cast<TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr()); + default: + break; + } + return false; +} + +size_t +ClangASTContext::GetTypeBitSize (clang::ASTContext *ast_context, void *clang_type) +{ + if (clang_type) + return ast_context->getTypeSize(QualType::getFromOpaquePtr(clang_type)); + return 0; +} + +size_t +ClangASTContext::GetTypeBitAlign (clang::ASTContext *ast_context, void *clang_type) +{ + if (clang_type) + return ast_context->getTypeAlign(QualType::getFromOpaquePtr(clang_type)); + return 0; +} + +bool +ClangASTContext::IsIntegerType (void * clang_type, bool &is_signed) +{ + if (!clang_type) + return false; + + QualType qual_type (QualType::getFromOpaquePtr(clang_type)); + const BuiltinType *builtin_type = dyn_cast<BuiltinType>(qual_type->getCanonicalTypeInternal()); + + if (builtin_type) + { + if (builtin_type->isInteger()) + is_signed = builtin_type->isSignedInteger(); + + return true; + } + + return false; +} + +bool +ClangASTContext::IsPointerType (void *clang_type, void **target_type) +{ + if (clang_type) + { + QualType qual_type (QualType::getFromOpaquePtr(clang_type)); + switch (qual_type->getTypeClass()) + { + case Type::ObjCObjectPointer: + if (target_type) + *target_type = cast<ObjCObjectPointerType>(qual_type)->getPointeeType().getAsOpaquePtr(); + return true; + case Type::BlockPointer: + if (target_type) + *target_type = cast<BlockPointerType>(qual_type)->getPointeeType().getAsOpaquePtr(); + return true; + case Type::Pointer: + if (target_type) + *target_type = cast<PointerType>(qual_type)->getPointeeType().getAsOpaquePtr(); + return true; + case Type::MemberPointer: + if (target_type) + *target_type = cast<MemberPointerType>(qual_type)->getPointeeType().getAsOpaquePtr(); + return true; + case Type::Typedef: + return ClangASTContext::IsPointerOrReferenceType (cast<TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr(), target_type); + default: + break; + } + } + return false; +} + +bool +ClangASTContext::IsFloatingPointType (void *clang_type, uint32_t &count, bool &is_complex) +{ + if (clang_type) + { + QualType qual_type (QualType::getFromOpaquePtr(clang_type)); + + if (const BuiltinType *BT = dyn_cast<BuiltinType>(qual_type->getCanonicalTypeInternal())) + { + clang::BuiltinType::Kind kind = BT->getKind(); + if (kind >= BuiltinType::Float && kind <= BuiltinType::LongDouble) + { + count = 1; + is_complex = false; + return true; + } + } + else if (const ComplexType *CT = dyn_cast<ComplexType>(qual_type->getCanonicalTypeInternal())) + { + if (IsFloatingPointType(CT->getElementType().getAsOpaquePtr(), count, is_complex)) + { + count = 2; + is_complex = true; + return true; + } + } + else if (const VectorType *VT = dyn_cast<VectorType>(qual_type->getCanonicalTypeInternal())) + { + if (IsFloatingPointType(VT->getElementType().getAsOpaquePtr(), count, is_complex)) + { + count = VT->getNumElements(); + is_complex = false; + return true; + } + } + } + return false; +} + + +bool +ClangASTContext::IsCStringType (void *clang_type, uint32_t &length) +{ + if (clang_type) + { + QualType qual_type (QualType::getFromOpaquePtr(clang_type)); + switch (qual_type->getTypeClass()) + { + case Type::ConstantArray: + { + ConstantArrayType *array = cast<ConstantArrayType>(qual_type.getTypePtr()); + QualType element_qual_type = array->getElementType(); + Type *canonical_type = element_qual_type->getCanonicalTypeInternal().getTypePtr(); + if (canonical_type && canonical_type->isCharType()) + { + // We know the size of the array and it could be a C string + // since it is an array of characters + length = array->getSize().getLimitedValue(); + return true; + } + } + break; + + case Type::Pointer: + { + PointerType *pointer_type = cast<PointerType>(qual_type.getTypePtr()); + Type *pointee_type_ptr = pointer_type->getPointeeType().getTypePtr(); + if (pointee_type_ptr) + { + Type *canonical_type_ptr = pointee_type_ptr->getCanonicalTypeInternal().getTypePtr(); + length = 0; // No length info, read until a NULL terminator is received + if (canonical_type_ptr) + return canonical_type_ptr->isCharType(); + else + return pointee_type_ptr->isCharType(); + } + } + break; + + case Type::Typedef: + return ClangASTContext::IsCStringType (cast<TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr(), length); + + case Type::LValueReference: + case Type::RValueReference: + { + ReferenceType *reference_type = cast<ReferenceType>(qual_type.getTypePtr()); + Type *pointee_type_ptr = reference_type->getPointeeType().getTypePtr(); + if (pointee_type_ptr) + { + Type *canonical_type_ptr = pointee_type_ptr->getCanonicalTypeInternal().getTypePtr(); + length = 0; // No length info, read until a NULL terminator is received + if (canonical_type_ptr) + return canonical_type_ptr->isCharType(); + else + return pointee_type_ptr->isCharType(); + } + } + break; + } + } + return false; +} + +bool +ClangASTContext::IsArrayType (void * clang_type, void **member_type, uint64_t *size) +{ + if (!clang_type) + return false; + + QualType qual_type (QualType::getFromOpaquePtr(clang_type)); + + switch (qual_type->getTypeClass()) + { + case Type::ConstantArray: + if (member_type) + *member_type = cast<ConstantArrayType>(qual_type)->getElementType().getAsOpaquePtr(); + if (size) + *size = cast<ConstantArrayType>(qual_type)->getSize().getLimitedValue(ULONG_LONG_MAX); + return true; + case Type::IncompleteArray: + if (member_type) + *member_type = cast<IncompleteArrayType>(qual_type)->getElementType().getAsOpaquePtr(); + if (size) + *size = 0; + return true; + case Type::VariableArray: + if (member_type) + *member_type = cast<VariableArrayType>(qual_type)->getElementType().getAsOpaquePtr(); + if (size) + *size = 0; + case Type::DependentSizedArray: + if (member_type) + *member_type = cast<DependentSizedArrayType>(qual_type)->getElementType().getAsOpaquePtr(); + if (size) + *size = 0; + return true; + } + return false; +} + + +#pragma mark Typedefs + +void * +ClangASTContext::CreateTypedefType (const char *name, void *clang_type, DeclContext *decl_ctx) +{ + if (clang_type) + { + QualType qual_type (QualType::getFromOpaquePtr(clang_type)); + ASTContext *ast_context = getASTContext(); + IdentifierTable *identifier_table = getIdentifierTable(); + assert (ast_context != NULL); + assert (identifier_table != NULL); + if (decl_ctx == NULL) + decl_ctx = ast_context->getTranslationUnitDecl(); + TypedefDecl *decl = TypedefDecl::Create(*ast_context, + decl_ctx, + SourceLocation(), + name ? &identifier_table->get(name) : NULL, // Identifier + ast_context->CreateTypeSourceInfo(qual_type)); + + // Get a uniqued QualType for the typedef decl type + return ast_context->getTypedefType (decl).getAsOpaquePtr(); + } + return NULL; +} + + +std::string +ClangASTContext::GetTypeName (void *opaque_qual_type) +{ + std::string return_name; + + clang::QualType qual_type(clang::QualType::getFromOpaquePtr(opaque_qual_type)); + + const clang::TypedefType *typedef_type = qual_type->getAs<clang::TypedefType>(); + if (typedef_type) + { + const clang::TypedefDecl *typedef_decl = typedef_type->getDecl(); + return_name = typedef_decl->getQualifiedNameAsString(); + } + else + { + return_name = qual_type.getAsString(); + } + + return return_name; +} + +// Disable this for now since I can't seem to get a nicely formatted float +// out of the APFloat class without just getting the float, double or quad +// and then using a formatted print on it which defeats the purpose. We ideally +// would like to get perfect string values for any kind of float semantics +// so we can support remote targets. The code below also requires a patch to +// llvm::APInt. +//bool +//ClangASTContext::ConvertFloatValueToString (ASTContext *ast_context, void *clang_type, const uint8_t* bytes, size_t byte_size, int apint_byte_order, std::string &float_str) +//{ +// uint32_t count = 0; +// bool is_complex = false; +// if (ClangASTContext::IsFloatingPointType (clang_type, count, is_complex)) +// { +// unsigned num_bytes_per_float = byte_size / count; +// unsigned num_bits_per_float = num_bytes_per_float * 8; +// +// float_str.clear(); +// uint32_t i; +// for (i=0; i<count; i++) +// { +// APInt ap_int(num_bits_per_float, bytes + i * num_bytes_per_float, (APInt::ByteOrder)apint_byte_order); +// bool is_ieee = false; +// APFloat ap_float(ap_int, is_ieee); +// char s[1024]; +// unsigned int hex_digits = 0; +// bool upper_case = false; +// +// if (ap_float.convertToHexString(s, hex_digits, upper_case, APFloat::rmNearestTiesToEven) > 0) +// { +// if (i > 0) +// float_str.append(", "); +// float_str.append(s); +// if (i == 1 && is_complex) +// float_str.append(1, 'i'); +// } +// } +// return !float_str.empty(); +// } +// return false; +//} + +size_t +ClangASTContext::ConvertStringToFloatValue (ASTContext *ast_context, void *clang_type, const char *s, uint8_t *dst, size_t dst_size) +{ + if (clang_type) + { + QualType qual_type (QualType::getFromOpaquePtr(clang_type)); + uint32_t count = 0; + bool is_complex = false; + if (ClangASTContext::IsFloatingPointType (clang_type, count, is_complex)) + { + // TODO: handle complex and vector types + if (count != 1) + return false; + + StringRef s_sref(s); + APFloat ap_float(ast_context->getFloatTypeSemantics(qual_type), s_sref); + + const uint64_t bit_size = ast_context->getTypeSize (qual_type); + const uint64_t byte_size = bit_size / 8; + if (dst_size >= byte_size) + { + if (bit_size == sizeof(float)*8) + { + float float32 = ap_float.convertToFloat(); + ::memcpy (dst, &float32, byte_size); + return byte_size; + } + else if (bit_size >= 64) + { + llvm::APInt ap_int(ap_float.bitcastToAPInt()); + ::memcpy (dst, ap_int.getRawData(), byte_size); + return byte_size; + } + } + } + } + return 0; +} diff --git a/lldb/source/Symbol/CompileUnit.cpp b/lldb/source/Symbol/CompileUnit.cpp new file mode 100644 index 00000000000..60a893b1d1e --- /dev/null +++ b/lldb/source/Symbol/CompileUnit.cpp @@ -0,0 +1,366 @@ +//===-- CompileUnit.cpp -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/LineTable.h" +#include "lldb/Core/Module.h" +#include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Symbol/VariableList.h" + +using namespace lldb; +using namespace lldb_private; + +CompileUnit::CompileUnit (Module *module, void *user_data, const char *pathname, const lldb::user_id_t cu_sym_id, Language::Type language) : + ModuleChild(module), + FileSpec (pathname), + UserID(cu_sym_id), + Language (language), + m_user_data (user_data), + m_flags (0), + m_functions (), + m_support_files (), + m_line_table_ap (), + m_variables() +{ + assert(module != NULL); +} + +CompileUnit::CompileUnit (Module *module, void *user_data, const FileSpec &fspec, const lldb::user_id_t cu_sym_id, Language::Type language) : + ModuleChild(module), + FileSpec (fspec), + UserID(cu_sym_id), + Language (language), + m_user_data (user_data), + m_flags (0), + m_functions (), + m_support_files (), + m_line_table_ap (), + m_variables() +{ + assert(module != NULL); +} + +CompileUnit::~CompileUnit () +{ +} + +void +CompileUnit::CalculateSymbolContext(SymbolContext* sc) +{ + sc->comp_unit = this; + GetModule()->CalculateSymbolContext(sc); +} + +void +CompileUnit::DumpSymbolContext(Stream *s) +{ + GetModule()->DumpSymbolContext(s); + s->Printf(", CompileUnit{0x%8.8x}", GetID()); +} + + + +//---------------------------------------------------------------------- +// Dump the current contents of this object. No functions that cause on +// demand parsing of functions, globals, statics are called, so this +// is a good function to call to get an idea of the current contents of +// the CompileUnit object. +//---------------------------------------------------------------------- +void +CompileUnit::Dump(Stream *s, bool show_context) const +{ + s->Printf("%.*p: ", (int)sizeof(void*) * 2, this); + s->Indent(); + *s << "CompileUnit" << (const UserID&)*this + << ", language = " << (const Language&)*this + << ", file='" << (const FileSpec&)*this << "'\n"; + +// m_types.Dump(s); + + if (m_variables.get()) + { + s->IndentMore(); + m_variables->Dump(s, show_context); + s->IndentLess(); + } + + if (!m_functions.empty()) + { + s->IndentMore(); + std::vector<FunctionSP>::const_iterator pos; + std::vector<FunctionSP>::const_iterator end = m_functions.end(); + for (pos = m_functions.begin(); pos != end; ++pos) + { + (*pos)->Dump(s, show_context); + } + + s->IndentLess(); + s->EOL(); + } +} + +//---------------------------------------------------------------------- +// Add a function to this compile unit +//---------------------------------------------------------------------- +void +CompileUnit::AddFunction(FunctionSP& funcSP) +{ + // TODO: order these by address + m_functions.push_back(funcSP); +} + +FunctionSP +CompileUnit::GetFunctionAtIndex (size_t idx) +{ + FunctionSP funcSP; + if (idx < m_functions.size()) + funcSP = m_functions[idx]; + return funcSP; +} + +//---------------------------------------------------------------------- +// Find functions using the a Mangled::Tokens token list. This +// function currently implements an interative approach designed to find +// all instances of certain functions. It isn't designed to the the +// quickest way to lookup functions as it will need to iterate through +// all functions and see if they match, though it does provide a powerful +// and context sensitive way to search for all functions with a certain +// name, all functions in a namespace, or all functions of a template +// type. See Mangled::Tokens::Parse() comments for more information. +// +// The function prototype will need to change to return a list of +// results. It was originally used to help debug the Mangled class +// and the Mangled::Tokens::MatchesQuery() function and it currently +// will print out a list of matching results for the functions that +// are currently in this compile unit. +// +// A FindFunctions method should be called prior to this that takes +// a regular function name (const char * or ConstString as a parameter) +// before resorting to this slower but more complete function. The +// other FindFunctions method should be able to take advantage of any +// accelerator tables available in the debug information (which is +// parsed by the SymbolFile parser plug-ins and registered with each +// Module). +//---------------------------------------------------------------------- +//void +//CompileUnit::FindFunctions(const Mangled::Tokens& tokens) +//{ +// if (!m_functions.empty()) +// { +// Stream s(stdout); +// std::vector<FunctionSP>::const_iterator pos; +// std::vector<FunctionSP>::const_iterator end = m_functions.end(); +// for (pos = m_functions.begin(); pos != end; ++pos) +// { +// const ConstString& demangled = (*pos)->Mangled().Demangled(); +// if (demangled) +// { +// const Mangled::Tokens& func_tokens = (*pos)->Mangled().GetTokens(); +// if (func_tokens.MatchesQuery (tokens)) +// s << "demangled MATCH found: " << demangled << "\n"; +// } +// } +// } +//} + +FunctionSP +CompileUnit::FindFunctionByUID (lldb::user_id_t func_uid) +{ + FunctionSP funcSP; + if (!m_functions.empty()) + { + std::vector<FunctionSP>::const_iterator pos; + std::vector<FunctionSP>::const_iterator end = m_functions.end(); + for (pos = m_functions.begin(); pos != end; ++pos) + { + if ((*pos)->GetID() == func_uid) + { + funcSP = *pos; + break; + } + } + } + return funcSP; +} + + +LineTable* +CompileUnit::GetLineTable() +{ + if (m_line_table_ap.get() == NULL) + { + if (m_flags.IsClear(flagsParsedLineTable)) + { + m_flags.Set(flagsParsedLineTable); + SymbolVendor* symbol_vendor = GetModule()->GetSymbolVendor(); + if (symbol_vendor) + { + SymbolContext sc; + CalculateSymbolContext(&sc); + symbol_vendor->ParseCompileUnitLineTable(sc); + } + } + } + return m_line_table_ap.get(); +} + +void +CompileUnit::SetLineTable(LineTable* line_table) +{ + if (line_table == NULL) + m_flags.Clear(flagsParsedLineTable); + else + m_flags.Set(flagsParsedLineTable); + m_line_table_ap.reset(line_table); +} + +VariableListSP +CompileUnit::GetVariableList(bool can_create) +{ + if (m_variables.get() == NULL && can_create) + { + SymbolContext sc; + CalculateSymbolContext(&sc); + assert(sc.module_sp); + sc.module_sp->GetSymbolVendor()->ParseVariablesForContext(sc); + } + + return m_variables; +} + +uint32_t +CompileUnit::FindLineEntry (uint32_t start_idx, uint32_t line, const FileSpec* file_spec_ptr, LineEntry *line_entry_ptr) +{ + uint32_t file_idx = 0; + + if (file_spec_ptr) + { + file_idx = GetSupportFiles().FindFileIndex (1, *file_spec_ptr); + if (file_idx == UINT32_MAX) + return UINT32_MAX; + } + else + { + // All the line table entries actually point to the version of the Compile + // Unit that is in the support files (the one at 0 was artifically added.) + // So prefer the one further on in the support files if it exists... + FileSpecList &support_files = GetSupportFiles(); + file_idx = support_files.FindFileIndex (1, support_files.GetFileSpecAtIndex(0)); + if (file_idx == UINT32_MAX) + file_idx = 0; + } + LineTable *line_table = GetLineTable(); + if (line_table) + return line_table->FindLineEntryIndexByFileIndex (start_idx, file_idx, line, true, line_entry_ptr); + return UINT32_MAX; +} + + + + +uint32_t +CompileUnit::ResolveSymbolContext +( + const FileSpec& file_spec, + uint32_t line, + bool check_inlines, + bool exact, + uint32_t resolve_scope, + SymbolContextList &sc_list +) +{ + const uint32_t prev_size = sc_list.GetSize(); + bool file_spec_matches_cu_file_spec = FileSpec::Compare(file_spec, this, !file_spec.GetDirectory().IsEmpty()) == 0; + if (check_inlines || file_spec_matches_cu_file_spec) + { + SymbolContext sc(GetModule()); + sc.comp_unit = this; + + uint32_t file_idx = UINT32_MAX; + + // If we are looking for inline functions only and we don't + // find it in the support files, we are done. + + if (check_inlines) + { + file_idx = sc.comp_unit->GetSupportFiles().FindFileIndex (1, file_spec); + if (file_idx == UINT32_MAX) + return 0; + } + + if (line != 0) + { + LineTable *line_table = sc.comp_unit->GetLineTable(); + + if (line_table != NULL) + { + // We will have already looked up the file index if + // we are searching for inline entries. + if (!check_inlines) + file_idx = sc.comp_unit->GetSupportFiles().FindFileIndex (1, file_spec); + + if (file_idx != UINT32_MAX) + { + uint32_t found_line; + + uint32_t line_idx = line_table->FindLineEntryIndexByFileIndex (0, file_idx, line, exact, &sc.line_entry); + found_line = sc.line_entry.line; + + while (line_idx != UINT_MAX) + { + sc_list.Append(sc); + line_idx = line_table->FindLineEntryIndexByFileIndex (line_idx + 1, file_idx, found_line, true, &sc.line_entry); + } + } + } + } + else if (file_spec_matches_cu_file_spec && !check_inlines) + { + // only append the context if we aren't looking for inline call sites + // by file and line and if the file spec matches that of the compile unit + sc_list.Append(sc); + } + + } + return sc_list.GetSize() - prev_size; +} + +void +CompileUnit::SetVariableList(VariableListSP &variables) +{ + m_variables = variables; +} + +FileSpecList& +CompileUnit::GetSupportFiles () +{ + if (m_support_files.GetSize() == 0) + { + if (m_flags.IsClear(flagsParsedSupportFiles)) + { + m_flags.Set(flagsParsedSupportFiles); + SymbolVendor* symbol_vendor = GetModule()->GetSymbolVendor(); + if (symbol_vendor) + { + SymbolContext sc; + CalculateSymbolContext(&sc); + symbol_vendor->ParseCompileUnitSupportFiles(sc, m_support_files); + } + } + } + return m_support_files; +} + +void * +CompileUnit::GetUserData () const +{ + return m_user_data; +} + + diff --git a/lldb/source/Symbol/DWARFCallFrameInfo.cpp b/lldb/source/Symbol/DWARFCallFrameInfo.cpp new file mode 100644 index 00000000000..febca924137 --- /dev/null +++ b/lldb/source/Symbol/DWARFCallFrameInfo.cpp @@ -0,0 +1,1344 @@ +//===-- DWARFCallFrameInfo.cpp ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +// C Includes +// C++ Includes +#include <list> + +// Other libraries and framework includes +// Project includes +#include "lldb/Symbol/DWARFCallFrameInfo.h" +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/Module.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Core/Section.h" +#include "lldb/Target/Thread.h" + +using namespace lldb; +using namespace lldb_private; + +static void +DumpRegisterName (Stream *s, Thread *thread, const ArchSpec *arch, uint32_t reg_kind, uint32_t reg_num) +{ + const char *reg_name = NULL; + RegisterContext *reg_ctx = NULL; + if (thread) + { + reg_ctx = thread->GetRegisterContext(); + if (reg_ctx) + reg_name = reg_ctx->GetRegisterName (reg_ctx->ConvertRegisterKindToRegisterNumber (reg_kind, reg_num)); + } + + if (reg_name == NULL && arch != NULL) + { + switch (reg_kind) + { + case eRegisterKindDWARF: reg_name = arch->GetRegisterName(reg_num, eRegisterKindDWARF); break; + case eRegisterKindGCC: reg_name = arch->GetRegisterName(reg_num, eRegisterKindGCC); break; + default: + break; + } + } + + if (reg_name) + s->PutCString(reg_name); + else + { + const char *reg_kind_name = NULL; + switch (reg_kind) + { + case eRegisterKindDWARF: reg_kind_name = "dwarf-reg"; break; + case eRegisterKindGCC: reg_kind_name = "compiler-reg"; break; + case eRegisterKindGeneric: reg_kind_name = "generic-reg"; break; + default: + break; + } + if (reg_kind_name) + s->Printf("%s(%u)", reg_kind_name, reg_num); + else + s->Printf("reg(%d.%u)", reg_kind, reg_num); + } +} + + +#pragma mark DWARFCallFrameInfo::RegisterLocation + +DWARFCallFrameInfo::RegisterLocation::RegisterLocation() : + m_type(isSame) +{ +} + + +bool +DWARFCallFrameInfo::RegisterLocation::operator == (const DWARFCallFrameInfo::RegisterLocation& rhs) const +{ + if (m_type != rhs.m_type) + return false; + switch (m_type) + { + case unspecified: + case isUndefined: + case isSame: + return true; + + case atCFAPlusOffset: + return m_location.offset == rhs.m_location.offset; + + case isCFAPlusOffset: + return m_location.offset == rhs.m_location.offset; + + case inOtherRegister: + return m_location.reg_num == rhs.m_location.reg_num; + + default: + break; + } + return false; +} + +void +DWARFCallFrameInfo::RegisterLocation::SetUnspecified() +{ + m_type = unspecified; +} + +void +DWARFCallFrameInfo::RegisterLocation::SetUndefined() +{ + m_type = isUndefined; +} + +void +DWARFCallFrameInfo::RegisterLocation::SetSame() +{ + m_type = isSame; +} + +void +DWARFCallFrameInfo::RegisterLocation::SetAtCFAPlusOffset(int64_t offset) +{ + m_type = atCFAPlusOffset; + m_location.offset = offset; +} + +void +DWARFCallFrameInfo::RegisterLocation::SetIsCFAPlusOffset(int64_t offset) +{ + m_type = isCFAPlusOffset; + m_location.offset = offset; +} + +void +DWARFCallFrameInfo::RegisterLocation::SetInRegister (uint32_t reg_num) +{ + m_type = inOtherRegister; + m_location.reg_num = reg_num; +} + +void +DWARFCallFrameInfo::RegisterLocation::SetAtDWARFExpression(const uint8_t *opcodes, uint32_t len) +{ + m_type = atDWARFExpression; + m_location.expr.opcodes = opcodes; + m_location.expr.length = len; +} + +void +DWARFCallFrameInfo::RegisterLocation::SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len) +{ + m_type = isDWARFExpression; + m_location.expr.opcodes = opcodes; + m_location.expr.length = len; +} + +void +DWARFCallFrameInfo::RegisterLocation::Dump(Stream *s, const DWARFCallFrameInfo &cfi, Thread *thread, const Row *row, uint32_t reg_num) const +{ + const ArchSpec *arch = cfi.GetArchitecture(); + const uint32_t reg_kind = cfi.GetRegisterKind(); + + DumpRegisterName (s, thread, arch, reg_kind, reg_num); + s->PutChar('='); + + switch (m_type) + { + case unspecified: + s->PutChar('?'); + break; + + case isUndefined: + s->PutCString("undefined"); + break; + + case isSame: + s->PutCString("same"); + break; + + case atCFAPlusOffset: + s->PutChar('['); + // Fall through to isCFAPlusOffset... + case isCFAPlusOffset: + { + DumpRegisterName (s, thread, arch, reg_kind, row->GetCFARegister()); + int32_t offset = row->GetCFAOffset() + m_location.offset; + if (offset != 0) + s->Printf("%-+d", offset); + if (m_type == atCFAPlusOffset) + s->PutChar(']'); + } + break; + + case inOtherRegister: + DumpRegisterName (s, thread, arch, reg_kind, m_location.reg_num); + break; + + case atDWARFExpression: + s->PutCString("[EXPR] "); + break; + + case isDWARFExpression: + s->PutCString("EXPR "); + break; + } +} + + +#pragma mark DWARFCallFrameInfo::Row + +DWARFCallFrameInfo::Row::Row() : + m_offset(0), + m_cfa_reg_num(0), + m_cfa_offset(0), + m_register_locations() +{ +} + +DWARFCallFrameInfo::Row::~Row() +{ +} + +void +DWARFCallFrameInfo::Row::Clear() +{ + m_register_locations.clear(); +} +bool +DWARFCallFrameInfo::Row::GetRegisterInfo (uint32_t reg_num, DWARFCallFrameInfo::RegisterLocation& register_location) const +{ + collection::const_iterator pos = m_register_locations.find(reg_num); + if (pos != m_register_locations.end()) + { + register_location = pos->second; + return true; + } + return false; +} + +void +DWARFCallFrameInfo::Row::SetRegisterInfo (uint32_t reg_num, const RegisterLocation& register_location) +{ + m_register_locations[reg_num] = register_location; +} + + +void +DWARFCallFrameInfo::Row::Dump(Stream* s, const DWARFCallFrameInfo &cfi, Thread *thread, lldb::addr_t base_addr) const +{ + const ArchSpec *arch = cfi.GetArchitecture(); + const uint32_t reg_kind = cfi.GetRegisterKind(); + collection::const_iterator pos, end = m_register_locations.end(); + s->Indent(); + s->Printf("0x%16.16llx: CFA=", m_offset + base_addr); + DumpRegisterName(s, thread, arch, reg_kind, m_cfa_reg_num); + if (m_cfa_offset != 0) + s->Printf("%-+lld", m_cfa_offset); + + for (pos = m_register_locations.begin(); pos != end; ++pos) + { + s->PutChar(' '); + pos->second.Dump(s, cfi, thread, this, pos->first); + } + s->EOL(); +} + + +#pragma mark DWARFCallFrameInfo::FDE + + +DWARFCallFrameInfo::FDE::FDE (dw_offset_t offset, const AddressRange &range) : + m_fde_offset (offset), + m_range (range), + m_row_list () +{ +} + +DWARFCallFrameInfo::FDE::~FDE() +{ +} + +void +DWARFCallFrameInfo::FDE::AppendRow (const Row &row) +{ + if (m_row_list.empty() || m_row_list.back().GetOffset() != row.GetOffset()) + m_row_list.push_back(row); + else + m_row_list.back() = row; +} + +void +DWARFCallFrameInfo::FDE::Dump (Stream *s, const DWARFCallFrameInfo &cfi, Thread* thread) const +{ + s->Indent(); + s->Printf("FDE{0x%8.8x} ", m_fde_offset); + m_range.Dump(s, NULL, Address::DumpStyleFileAddress); + lldb::addr_t fde_base_addr = m_range.GetBaseAddress().GetFileAddress(); + s->EOL(); + s->IndentMore(); + collection::const_iterator pos, end = m_row_list.end(); + for (pos = m_row_list.begin(); pos != end; ++pos) + { + pos->Dump(s, cfi, thread, fde_base_addr); + } + s->IndentLess(); +} + +const AddressRange & +DWARFCallFrameInfo::FDE::GetAddressRange() const +{ + return m_range; +} + +bool +DWARFCallFrameInfo::FDE::IsValidRowIndex (uint32_t idx) const +{ + return idx < m_row_list.size(); +} + +const DWARFCallFrameInfo::Row& +DWARFCallFrameInfo::FDE::GetRowAtIndex (uint32_t idx) +{ + // You must call IsValidRowIndex(idx) first before calling this!!! + return m_row_list[idx]; +} +#pragma mark DWARFCallFrameInfo::FDEInfo + +DWARFCallFrameInfo::FDEInfo::FDEInfo () : + fde_offset (0), + fde_sp() +{ +} + +DWARFCallFrameInfo::FDEInfo::FDEInfo (off_t offset) : + fde_offset(offset), + fde_sp() +{ +} + +#pragma mark DWARFCallFrameInfo::CIE + +DWARFCallFrameInfo::CIE::CIE(dw_offset_t offset) : + cie_offset (offset), + version (0), + augmentation(), + code_align (0), + data_align (0), + return_addr_reg_num (0), + inst_offset (0), + inst_length (0), + ptr_encoding (DW_GNU_EH_PE_absptr) +{ +} + + +DWARFCallFrameInfo::CIE::~CIE() +{ +} + +void +DWARFCallFrameInfo::CIE::Dump(Stream *s, Thread* thread, const ArchSpec *arch, uint32_t reg_kind) const +{ + s->Indent(); + s->Printf("CIE{0x%8.8x} version=%u, code_align=%u, data_align=%d, return_addr_reg=", cie_offset, version, code_align, data_align); + DumpRegisterName(s, thread, arch, reg_kind, return_addr_reg_num); + s->Printf(", instr_offset=0x%8.8x, instr_length=%u, ptr_encoding=0x%02x\n", + inst_offset, + inst_length, + ptr_encoding); +} + +#pragma mark DWARFCallFrameInfo::CIE + +DWARFCallFrameInfo::DWARFCallFrameInfo(ObjectFile *objfile, Section *section, uint32_t reg_kind) : + m_objfile (objfile), + m_section (section), + m_reg_kind (reg_kind), // The flavor of registers that the CFI data uses (One of the defines that starts with "LLDB_REGKIND_") + m_cfi_data (), + m_cie_map (), + m_fde_map () +{ + if (objfile && section) + { + section->ReadSectionDataFromObjectFile (objfile, m_cfi_data); + } +} + +DWARFCallFrameInfo::~DWARFCallFrameInfo() +{ +} + +bool +DWARFCallFrameInfo::IsEHFrame() const +{ + return (m_reg_kind == eRegisterKindGCC); +} + +const ArchSpec * +DWARFCallFrameInfo::GetArchitecture() const +{ + if (m_objfile && m_objfile->GetModule()) + return &m_objfile->GetModule()->GetArchitecture(); + return NULL; +} + +uint32_t +DWARFCallFrameInfo::GetRegisterKind () const +{ + return m_reg_kind; +} + +void +DWARFCallFrameInfo::SetRegisterKind (uint32_t reg_kind) +{ + m_reg_kind = reg_kind; +} + + + + +const DWARFCallFrameInfo::CIE* +DWARFCallFrameInfo::GetCIE(dw_offset_t cie_offset) +{ + Index (); + + cie_map_t::iterator pos = m_cie_map.find(cie_offset); + + if (pos != m_cie_map.end()) + { + // Parse and cache the CIE + if (pos->second.get() == NULL) + pos->second = ParseCIE (cie_offset); + + return pos->second.get(); + } + return NULL; +} + +DWARFCallFrameInfo::CIE::shared_ptr +DWARFCallFrameInfo::ParseCIE (const dw_offset_t cie_offset) +{ + CIE::shared_ptr cie_sp(new CIE(cie_offset)); + const bool for_eh_frame = IsEHFrame(); + dw_offset_t offset = cie_offset; + const uint32_t length = m_cfi_data.GetU32(&offset); + const dw_offset_t cie_id = m_cfi_data.GetU32(&offset); + const dw_offset_t end_offset = cie_offset + length + 4; + if (length > 0 && (!for_eh_frame && cie_id == 0xfffffffful) || (for_eh_frame && cie_id == 0ul)) + { + size_t i; + // cie.offset = cie_offset; + // cie.length = length; + // cie.cieID = cieID; + cie_sp->ptr_encoding = DW_GNU_EH_PE_absptr; + cie_sp->version = m_cfi_data.GetU8(&offset); + + for (i=0; i<CFI_AUG_MAX_SIZE; ++i) + { + cie_sp->augmentation[i] = m_cfi_data.GetU8(&offset); + if (cie_sp->augmentation[i] == '\0') + { + // Zero out remaining bytes in augmentation string + for (size_t j = i+1; j<CFI_AUG_MAX_SIZE; ++j) + cie_sp->augmentation[j] = '\0'; + + break; + } + } + + if (i == CFI_AUG_MAX_SIZE && cie_sp->augmentation[CFI_AUG_MAX_SIZE-1] != '\0') + { + fprintf(stderr, "CIE parse error: CIE augmentation string was too large for the fixed sized buffer of %d bytes.\n", CFI_AUG_MAX_SIZE); + return cie_sp; + } + cie_sp->code_align = (uint32_t)m_cfi_data.GetULEB128(&offset); + cie_sp->data_align = (int32_t)m_cfi_data.GetSLEB128(&offset); + cie_sp->return_addr_reg_num = m_cfi_data.GetU8(&offset); + + if (cie_sp->augmentation[0]) + { + // Get the length of the eh_frame augmentation data + // which starts with a ULEB128 length in bytes + const size_t aug_data_len = (size_t)m_cfi_data.GetULEB128(&offset); + const size_t aug_data_end = offset + aug_data_len; + const size_t aug_str_len = strlen(cie_sp->augmentation); + // A 'z' may be present as the first character of the string. + // If present, the Augmentation Data field shall be present. + // The contents of the Augmentation Data shall be intepreted + // according to other characters in the Augmentation String. + if (cie_sp->augmentation[0] == 'z') + { + // Extract the Augmentation Data + size_t aug_str_idx = 0; + for (aug_str_idx = 1; aug_str_idx < aug_str_len; aug_str_idx++) + { + char aug = cie_sp->augmentation[aug_str_idx]; + switch (aug) + { + case 'L': + // Indicates the presence of one argument in the + // Augmentation Data of the CIE, and a corresponding + // argument in the Augmentation Data of the FDE. The + // argument in the Augmentation Data of the CIE is + // 1-byte and represents the pointer encoding used + // for the argument in the Augmentation Data of the + // FDE, which is the address of a language-specific + // data area (LSDA). The size of the LSDA pointer is + // specified by the pointer encoding used. + m_cfi_data.GetU8(&offset); + break; + + case 'P': + // Indicates the presence of two arguments in the + // Augmentation Data of the cie_sp-> The first argument + // is 1-byte and represents the pointer encoding + // used for the second argument, which is the + // address of a personality routine handler. The + // size of the personality routine pointer is + // specified by the pointer encoding used. + { + uint8_t arg_ptr_encoding = m_cfi_data.GetU8(&offset); + m_cfi_data.GetGNUEHPointer(&offset, arg_ptr_encoding, LLDB_INVALID_ADDRESS, LLDB_INVALID_ADDRESS, LLDB_INVALID_ADDRESS); + } + break; + + case 'R': + // A 'R' may be present at any position after the + // first character of the string. The Augmentation + // Data shall include a 1 byte argument that + // represents the pointer encoding for the address + // pointers used in the FDE. + cie_sp->ptr_encoding = m_cfi_data.GetU8(&offset); + break; + } + } + } + else if (strcmp(cie_sp->augmentation, "eh") == 0) + { + // If the Augmentation string has the value "eh", then + // the EH Data field shall be present + } + + // Set the offset to be the end of the augmentation data just in case + // we didn't understand any of the data. + offset = (uint32_t)aug_data_end; + } + + if (end_offset > offset) + { + cie_sp->inst_offset = offset; + cie_sp->inst_length = end_offset - offset; + } + } + + return cie_sp; +} + +DWARFCallFrameInfo::FDE::shared_ptr +DWARFCallFrameInfo::ParseFDE(const dw_offset_t fde_offset) +{ + const bool for_eh_frame = IsEHFrame(); + FDE::shared_ptr fde_sp; + + dw_offset_t offset = fde_offset; + const uint32_t length = m_cfi_data.GetU32(&offset); + dw_offset_t cie_offset = m_cfi_data.GetU32(&offset); + const dw_offset_t end_offset = fde_offset + length + 4; + + // Translate the CIE_id from the eh_frame format, which + // is relative to the FDE offset, into a __eh_frame section + // offset + if (for_eh_frame) + cie_offset = offset - (cie_offset + 4); + + const CIE* cie = GetCIE(cie_offset); + if (cie) + { + const lldb::addr_t pc_rel_addr = m_section->GetFileAddress(); + const lldb::addr_t text_addr = LLDB_INVALID_ADDRESS; + const lldb::addr_t data_addr = LLDB_INVALID_ADDRESS; + lldb::addr_t range_base = m_cfi_data.GetGNUEHPointer(&offset, cie->ptr_encoding, pc_rel_addr, text_addr, data_addr); + lldb::addr_t range_len = m_cfi_data.GetGNUEHPointer(&offset, cie->ptr_encoding & DW_GNU_EH_PE_MASK_ENCODING, pc_rel_addr, text_addr, data_addr); + + if (cie->augmentation[0] == 'z') + { + uint32_t aug_data_len = (uint32_t)m_cfi_data.GetULEB128(&offset); + offset += aug_data_len; + } + + AddressRange fde_range (range_base, range_len, m_objfile->GetSectionList ()); + fde_sp.reset(new FDE(fde_offset, fde_range)); + if (offset < end_offset) + { + dw_offset_t fde_instr_offset = offset; + uint32_t fde_instr_length = end_offset - offset; + if (cie->inst_length > 0) + ParseInstructions(cie, fde_sp.get(), cie->inst_offset, cie->inst_length); + ParseInstructions(cie, fde_sp.get(), fde_instr_offset, fde_instr_length); + } + } + return fde_sp; +} + +const DWARFCallFrameInfo::FDE * +DWARFCallFrameInfo::FindFDE(const Address &addr) +{ + Index (); + + VMRange find_range(addr.GetFileAddress(), 0); + fde_map_t::iterator pos = m_fde_map.lower_bound (find_range); + fde_map_t::iterator end = m_fde_map.end(); + + if (pos != end) + { + if (pos->first.Contains(find_range.GetBaseAddress())) + { + // Parse and cache the FDE if we already haven't + if (pos->second.fde_sp.get() == NULL) + pos->second.fde_sp = ParseFDE(pos->second.fde_offset); + + return pos->second.fde_sp.get(); + } + } + return NULL; +} + + +void +DWARFCallFrameInfo::Index () +{ + if (m_flags.IsClear(eFlagParsedIndex)) + { + m_flags.Set (eFlagParsedIndex); + const bool for_eh_frame = IsEHFrame(); + CIE::shared_ptr empty_cie_sp; + dw_offset_t offset = 0; + // Parse all of the CIEs first since we will need them to be able to + // properly parse the FDE addresses due to them possibly having + // GNU pointer encodings in their augmentations... + while (m_cfi_data.ValidOffsetForDataOfSize(offset, 8)) + { + const dw_offset_t curr_offset = offset; + const uint32_t length = m_cfi_data.GetU32(&offset); + const dw_offset_t next_offset = offset + length; + const dw_offset_t cie_id = m_cfi_data.GetU32(&offset); + + bool is_cie = for_eh_frame ? cie_id == 0 : cie_id == UINT32_MAX; + if (is_cie) + m_cie_map[curr_offset]= ParseCIE(curr_offset); + + offset = next_offset; + } + + // Now go back through and index all FDEs + offset = 0; + const lldb::addr_t pc_rel_addr = m_section->GetFileAddress(); + const lldb::addr_t text_addr = LLDB_INVALID_ADDRESS; + const lldb::addr_t data_addr = LLDB_INVALID_ADDRESS; + while (m_cfi_data.ValidOffsetForDataOfSize(offset, 8)) + { + const dw_offset_t curr_offset = offset; + const uint32_t length = m_cfi_data.GetU32(&offset); + const dw_offset_t next_offset = offset + length; + const dw_offset_t cie_id = m_cfi_data.GetU32(&offset); + + bool is_fde = for_eh_frame ? cie_id != 0 : cie_id != UINT32_MAX; + if (is_fde) + { + dw_offset_t cie_offset; + if (for_eh_frame) + cie_offset = offset - (cie_id + 4); + else + cie_offset = cie_id; + + const CIE* cie = GetCIE(cie_offset); + assert(cie); + lldb::addr_t addr = m_cfi_data.GetGNUEHPointer(&offset, cie->ptr_encoding, pc_rel_addr, text_addr, data_addr); + lldb::addr_t length = m_cfi_data.GetGNUEHPointer(&offset, cie->ptr_encoding & DW_GNU_EH_PE_MASK_ENCODING, pc_rel_addr, text_addr, data_addr); + m_fde_map[VMRange(addr, addr + length)] = FDEInfo(curr_offset); + } + + offset = next_offset; + } + } +} + +//---------------------------------------------------------------------- +// Parse instructions for a FDE. The initial instruction for the CIE +// are parsed first, then the instructions for the FDE are parsed +//---------------------------------------------------------------------- +void +DWARFCallFrameInfo::ParseInstructions(const CIE *cie, FDE *fde, dw_offset_t instr_offset, uint32_t instr_length) +{ + if (cie != NULL && fde == NULL) + return; + + uint32_t reg_num = 0; + int32_t op_offset = 0; + uint32_t tmp_uval32; + uint32_t code_align = cie->code_align; + int32_t data_align = cie->data_align; + typedef std::list<Row> RowStack; + + RowStack row_stack; + Row row; + if (fde->IsValidRowIndex(0)) + row = fde->GetRowAtIndex(0); + + dw_offset_t offset = instr_offset; + const dw_offset_t end_offset = instr_offset + instr_length; + RegisterLocation reg_location; + while (m_cfi_data.ValidOffset(offset) && offset < end_offset) + { + uint8_t inst = m_cfi_data.GetU8(&offset); + uint8_t primary_opcode = inst & 0xC0; + uint8_t extended_opcode = inst & 0x3F; + + if (primary_opcode) + { + switch (primary_opcode) + { + case DW_CFA_advance_loc : // (Row Creation Instruction) + { // 0x40 - high 2 bits are 0x1, lower 6 bits are delta + // takes a single argument that represents a constant delta. The + // required action is to create a new table row with a location + // value that is computed by taking the current entry's location + // value and adding (delta * code_align). All other + // values in the new row are initially identical to the current row. + fde->AppendRow(row); + row.SlideOffset(extended_opcode * code_align); + } + break; + + case DW_CFA_offset : + { // 0x80 - high 2 bits are 0x2, lower 6 bits are register + // takes two arguments: an unsigned LEB128 constant representing a + // factored offset and a register number. The required action is to + // change the rule for the register indicated by the register number + // to be an offset(N) rule with a value of + // (N = factored offset * data_align). + reg_num = extended_opcode; + op_offset = (int32_t)m_cfi_data.GetULEB128(&offset) * data_align; + reg_location.SetAtCFAPlusOffset(op_offset); + row.SetRegisterInfo (reg_num, reg_location); + } + break; + + case DW_CFA_restore : + { // 0xC0 - high 2 bits are 0x3, lower 6 bits are register + // takes a single argument that represents a register number. The + // required action is to change the rule for the indicated register + // to the rule assigned it by the initial_instructions in the CIE. + reg_num = extended_opcode; + // We only keep enough register locations around to + // unwind what is in our thread, and these are organized + // by the register index in that state, so we need to convert our + // GCC register number from the EH frame info, to a registe index + + if (fde->IsValidRowIndex(0) && fde->GetRowAtIndex(0).GetRegisterInfo(reg_num, reg_location)) + row.SetRegisterInfo (reg_num, reg_location); + } + break; + } + } + else + { + switch (extended_opcode) + { + case DW_CFA_nop : // 0x0 + break; + + case DW_CFA_set_loc : // 0x1 (Row Creation Instruction) + { + // DW_CFA_set_loc takes a single argument that represents an address. + // The required action is to create a new table row using the + // specified address as the location. All other values in the new row + // are initially identical to the current row. The new location value + // should always be greater than the current one. + fde->AppendRow(row); + row.SetOffset(m_cfi_data.GetPointer(&offset) - fde->GetAddressRange().GetBaseAddress().GetFileAddress()); + } + break; + + case DW_CFA_advance_loc1 : // 0x2 (Row Creation Instruction) + { + // takes a single uword argument that represents a constant delta. + // This instruction is identical to DW_CFA_advance_loc except for the + // encoding and size of the delta argument. + fde->AppendRow(row); + row.SlideOffset (m_cfi_data.GetU8(&offset) * code_align); + } + break; + + case DW_CFA_advance_loc2 : // 0x3 (Row Creation Instruction) + { + // takes a single uword argument that represents a constant delta. + // This instruction is identical to DW_CFA_advance_loc except for the + // encoding and size of the delta argument. + fde->AppendRow(row); + row.SlideOffset (m_cfi_data.GetU16(&offset) * code_align); + } + break; + + case DW_CFA_advance_loc4 : // 0x4 (Row Creation Instruction) + { + // takes a single uword argument that represents a constant delta. + // This instruction is identical to DW_CFA_advance_loc except for the + // encoding and size of the delta argument. + fde->AppendRow(row); + row.SlideOffset (m_cfi_data.GetU32(&offset) * code_align); + } + break; + + case DW_CFA_offset_extended : // 0x5 + { + // takes two unsigned LEB128 arguments representing a register number + // and a factored offset. This instruction is identical to DW_CFA_offset + // except for the encoding and size of the register argument. + reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); + op_offset = (int32_t)m_cfi_data.GetULEB128(&offset) * data_align; + reg_location.SetAtCFAPlusOffset(op_offset); + row.SetRegisterInfo (reg_num, reg_location); + } + break; + + case DW_CFA_restore_extended : // 0x6 + { + // takes a single unsigned LEB128 argument that represents a register + // number. This instruction is identical to DW_CFA_restore except for + // the encoding and size of the register argument. + reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); + if (fde->IsValidRowIndex(0) && fde->GetRowAtIndex(0).GetRegisterInfo(reg_num, reg_location)) + row.SetRegisterInfo (reg_num, reg_location); + } + break; + + case DW_CFA_undefined : // 0x7 + { + // takes a single unsigned LEB128 argument that represents a register + // number. The required action is to set the rule for the specified + // register to undefined. + reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); + reg_location.SetUndefined(); + row.SetRegisterInfo (reg_num, reg_location); + } + break; + + case DW_CFA_same_value : // 0x8 + { + // takes a single unsigned LEB128 argument that represents a register + // number. The required action is to set the rule for the specified + // register to same value. + reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); + reg_location.SetSame(); + row.SetRegisterInfo (reg_num, reg_location); + } + break; + + case DW_CFA_register : // 0x9 + { + // takes two unsigned LEB128 arguments representing register numbers. + // The required action is to set the rule for the first register to be + // the second register. + + reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); + uint32_t other_reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); + reg_location.SetInRegister(other_reg_num); + row.SetRegisterInfo (reg_num, reg_location); + } + break; + + case DW_CFA_remember_state : // 0xA + // These instructions define a stack of information. Encountering the + // DW_CFA_remember_state instruction means to save the rules for every + // register on the current row on the stack. Encountering the + // DW_CFA_restore_state instruction means to pop the set of rules off + // the stack and place them in the current row. (This operation is + // useful for compilers that move epilogue code into the body of a + // function.) + row_stack.push_back(row); + break; + + case DW_CFA_restore_state : // 0xB + // These instructions define a stack of information. Encountering the + // DW_CFA_remember_state instruction means to save the rules for every + // register on the current row on the stack. Encountering the + // DW_CFA_restore_state instruction means to pop the set of rules off + // the stack and place them in the current row. (This operation is + // useful for compilers that move epilogue code into the body of a + // function.) + { + row = row_stack.back(); + row_stack.pop_back(); + } + break; + + case DW_CFA_def_cfa : // 0xC (CFA Definition Instruction) + { + // Takes two unsigned LEB128 operands representing a register + // number and a (non-factored) offset. The required action + // is to define the current CFA rule to use the provided + // register and offset. + reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); + op_offset = (int32_t)m_cfi_data.GetULEB128(&offset); + row.SetCFARegister (reg_num); + row.SetCFAOffset (op_offset); + } + break; + + case DW_CFA_def_cfa_register : // 0xD (CFA Definition Instruction) + { + // takes a single unsigned LEB128 argument representing a register + // number. The required action is to define the current CFA rule to + // use the provided register (but to keep the old offset). + reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); + row.SetCFARegister (reg_num); + } + break; + + case DW_CFA_def_cfa_offset : // 0xE (CFA Definition Instruction) + { + // Takes a single unsigned LEB128 operand representing a + // (non-factored) offset. The required action is to define + // the current CFA rule to use the provided offset (but + // to keep the old register). + op_offset = (int32_t)m_cfi_data.GetULEB128(&offset); + row.SetCFAOffset (op_offset); + } + break; + + case DW_CFA_def_cfa_expression : // 0xF (CFA Definition Instruction) + { + size_t block_len = (size_t)m_cfi_data.GetULEB128(&offset); + offset += (uint32_t)block_len; + } + break; + + case DW_CFA_expression : // 0x10 + { + // Takes two operands: an unsigned LEB128 value representing + // a register number, and a DW_FORM_block value representing a DWARF + // expression. The required action is to change the rule for the + // register indicated by the register number to be an expression(E) + // rule where E is the DWARF expression. That is, the DWARF + // expression computes the address. The value of the CFA is + // pushed on the DWARF evaluation stack prior to execution of + // the DWARF expression. + reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); + uint32_t block_len = (uint32_t)m_cfi_data.GetULEB128(&offset); + const uint8_t *block_data = (uint8_t *)m_cfi_data.GetData(&offset, block_len); + + reg_location.SetAtDWARFExpression(block_data, block_len); + row.SetRegisterInfo (reg_num, reg_location); + } + break; + + case DW_CFA_offset_extended_sf : // 0x11 + { + // takes two operands: an unsigned LEB128 value representing a + // register number and a signed LEB128 factored offset. This + // instruction is identical to DW_CFA_offset_extended except + //that the second operand is signed and factored. + reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); + op_offset = (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align; + reg_location.SetAtCFAPlusOffset(op_offset); + row.SetRegisterInfo (reg_num, reg_location); + } + break; + + case DW_CFA_def_cfa_sf : // 0x12 (CFA Definition Instruction) + { + // Takes two operands: an unsigned LEB128 value representing + // a register number and a signed LEB128 factored offset. + // This instruction is identical to DW_CFA_def_cfa except + // that the second operand is signed and factored. + reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); + op_offset = (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align; + row.SetCFARegister (reg_num); + row.SetCFAOffset (op_offset); + } + break; + + case DW_CFA_def_cfa_offset_sf : // 0x13 (CFA Definition Instruction) + { + // takes a signed LEB128 operand representing a factored + // offset. This instruction is identical to DW_CFA_def_cfa_offset + // except that the operand is signed and factored. + op_offset = (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align; + row.SetCFAOffset (op_offset); + } + break; + + case DW_CFA_val_expression : // 0x16 + { + // takes two operands: an unsigned LEB128 value representing a register + // number, and a DW_FORM_block value representing a DWARF expression. + // The required action is to change the rule for the register indicated + // by the register number to be a val_expression(E) rule where E is the + // DWARF expression. That is, the DWARF expression computes the value of + // the given register. The value of the CFA is pushed on the DWARF + // evaluation stack prior to execution of the DWARF expression. + reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset); + uint32_t block_len = (uint32_t)m_cfi_data.GetULEB128(&offset); + const uint8_t* block_data = (uint8_t*)m_cfi_data.GetData(&offset, block_len); +//#if defined(__i386__) || defined(__x86_64__) +// // The EH frame info for EIP and RIP contains code that looks for traps to +// // be a specific type and increments the PC. +// // For i386: +// // DW_CFA_val_expression where: +// // eip = DW_OP_breg6(+28), DW_OP_deref, DW_OP_dup, DW_OP_plus_uconst(0x34), +// // DW_OP_deref, DW_OP_swap, DW_OP_plus_uconst(0), DW_OP_deref, +// // DW_OP_dup, DW_OP_lit3, DW_OP_ne, DW_OP_swap, DW_OP_lit4, DW_OP_ne, +// // DW_OP_and, DW_OP_plus +// // This basically does a: +// // eip = ucontenxt.mcontext32->gpr.eip; +// // if (ucontenxt.mcontext32->exc.trapno != 3 && ucontenxt.mcontext32->exc.trapno != 4) +// // eip++; +// // +// // For x86_64: +// // DW_CFA_val_expression where: +// // rip = DW_OP_breg3(+48), DW_OP_deref, DW_OP_dup, DW_OP_plus_uconst(0x90), DW_OP_deref, +// // DW_OP_swap, DW_OP_plus_uconst(0), DW_OP_deref_size(4), DW_OP_dup, DW_OP_lit3, +// // DW_OP_ne, DW_OP_swap, DW_OP_lit4, DW_OP_ne, DW_OP_and, DW_OP_plus +// // This basically does a: +// // rip = ucontenxt.mcontext64->gpr.rip; +// // if (ucontenxt.mcontext64->exc.trapno != 3 && ucontenxt.mcontext64->exc.trapno != 4) +// // rip++; +// // The trap comparisons and increments are not needed as it hoses up the unwound PC which +// // is expected to point at least past the instruction that causes the fault/trap. So we +// // take it out by trimming the expression right at the first "DW_OP_swap" opcodes +// if (block_data != NULL && thread->GetPCRegNum(Thread::GCC) == reg_num) +// { +// if (thread->Is64Bit()) +// { +// if (block_len > 9 && block_data[8] == DW_OP_swap && block_data[9] == DW_OP_plus_uconst) +// block_len = 8; +// } +// else +// { +// if (block_len > 8 && block_data[7] == DW_OP_swap && block_data[8] == DW_OP_plus_uconst) +// block_len = 7; +// } +// } +//#endif + reg_location.SetIsDWARFExpression(block_data, block_len); + row.SetRegisterInfo (reg_num, reg_location); + } + break; + + case DW_CFA_val_offset : // 0x14 + case DW_CFA_val_offset_sf : // 0x15 + default: + tmp_uval32 = extended_opcode; + break; + } + } + } + fde->AppendRow(row); +} + +void +DWARFCallFrameInfo::ParseAll() +{ + Index(); + fde_map_t::iterator pos, end = m_fde_map.end(); + for (pos = m_fde_map.begin(); pos != end; ++ pos) + { + if (pos->second.fde_sp.get() == NULL) + pos->second.fde_sp = ParseFDE(pos->second.fde_offset); + } +} + + +//bool +//DWARFCallFrameInfo::UnwindRegisterAtIndex +//( +// const uint32_t reg_idx, +// const Thread* currState, +// const DWARFCallFrameInfo::Row* row, +// mapped_memory_t * memCache, +// Thread* unwindState +//) +//{ +// bool get_reg_success = false; +// +// const RegLocation* regLocation = row->regs.GetRegisterInfo(reg_idx); +// +// // On some systems, we may not get unwind info for the program counter, +// // but the return address register can be used to get that information. +// if (reg_idx == currState->GetPCRegNum(Thread::Index)) +// { +// const RegLocation* returnAddrRegLocation = row->regs.GetRegisterInfo(currState->GetRARegNum(Thread::Index)); +// if (regLocation == NULL) +// { +// // We have nothing to the program counter, so lets see if this +// // thread state has a return address (link register) that can +// // help us track down the previous PC +// regLocation = returnAddrRegLocation; +// } +// else if (regLocation->type == RegLocation::unspecified) +// { +// // We did have a location that didn't specify a value for unwinding +// // the PC, so if there is a info for the return return address +// // register (link register) lets use that +// if (returnAddrRegLocation) +// regLocation = returnAddrRegLocation; +// } +// } +// +// if (regLocation) +// { +// mach_vm_address_t unwoundRegValue = INVALID_VMADDR; +// switch (regLocation->type) +// { +// case RegLocation::undefined: +// // Register is not available, mark it as invalid +// unwindState->SetRegisterIsValid(reg_idx, Thread::Index, false); +// return true; +// +// case RegLocation::unspecified: +// // Nothing to do if it is the same +// return true; +// +// case RegLocation::same: +// // Nothing to do if it is the same +// return true; +// +// case RegLocation::atFPPlusOffset: +// case RegLocation::isFPPlusOffset: +// { +// uint64_t unwindAddress = currState->GetRegisterValue(row->cfa_register, Thread::GCC, INVALID_VMADDR, &get_reg_success); +// +// if (get_reg_success) +// { +// unwindAddress += row->cfa_offset + regLocation->location.offset; +// +// if (regLocation->type == RegLocation::isFPPlusOffset) +// { +// unwindState->SetRegisterValue(reg_idx, Thread::Index, unwindAddress); +// return true; +// } +// else +// { +// kern_return_t err = mapped_memory_read_pointer(memCache, unwindAddress, &unwoundRegValue); +// if (err != KERN_SUCCESS) +// { +// unwindState->SetRegisterIsValid(reg_idx, Thread::Index, false); +// return false; +// } +// unwindState->SetRegisterValue(reg_idx, Thread::Index, unwoundRegValue); +// return true; +// } +// } +// else +// { +// unwindState->SetRegisterIsValid(reg_idx, Thread::Index, false); +// } +// return false; +// } +// break; +// +// case RegLocation::atDWARFExpression: +// case RegLocation::isDWARFExpression: +// { +// bool swap = false; +// DWARFExpressionBaton baton = { currState, memCache, swap }; +// uint64_t expr_result = 0; +// CSBinaryDataRef opcodes(regLocation->location.expr.opcodes, regLocation->location.expr.length, swap); +// opcodes.SetPointerSize(currState->Is64Bit() ? 8 : 4); +// const char * expr_err = CSDWARFExpression::Evaluate(DWARFExpressionReadMemoryDCScriptInterpreter::Type, +// DWARFExpressionReadRegisterDCScriptInterpreter::Type, +// &baton, +// opcodes, +// 0, +// regLocation->location.expr.length, +// NULL, +// expr_result); +// if (expr_err == NULL) +// { +// // SUCCESS! +// if (regLocation->type == RegLocation::isDWARFExpression) +// { +// unwindState->SetRegisterValue(reg_idx, Thread::Index, expr_result); +// return true; +// } +// else +// { +// kern_return_t err = mapped_memory_read_pointer(memCache, expr_result, &unwoundRegValue); +// if (err != KERN_SUCCESS) +// { +// unwindState->SetRegisterIsValid(reg_idx, Thread::Index, false); +// return false; +// } +// unwindState->SetRegisterValue(reg_idx, Thread::Index, unwoundRegValue); +// return true; +// } +// } +// else +// { +// // FAIL +// unwindState->SetRegisterIsValid(reg_idx, Thread::Index, false); +// } +// return false; +// } +// break; +// +// +// case RegLocation::inRegister: +// // The value is in another register. +// unwoundRegValue = currState->GetRegisterValue(regLocation->location.reg, Thread::GCC, 0, &get_reg_success); +// if (get_reg_success) +// { +// unwindState->SetRegisterValue(reg_idx, Thread::Index, unwoundRegValue); +// return true; +// } +// return false; +// +// default: +// break; +// } +// } +// +// if (reg_idx == currState->GetSPRegNum(Thread::Index)) +// { +// uint64_t cfa = currState->GetRegisterValue(row->cfa_register, Thread::GCC, 0, &get_reg_success); +// if (get_reg_success) +// { +// return unwindState->SetSP(cfa + row->cfa_offset); +// } +// else +// { +// unwindState->SetRegisterIsValid(reg_idx, Thread::Index, false); +// return false; +// } +// } +// +// return false; +//} + +void +DWARFCallFrameInfo::Dump(Stream *s, Thread *thread) const +{ + s->Indent(); + s->Printf("DWARFCallFrameInfo for "); + *s << m_objfile->GetFileSpec(); + if (m_flags.IsSet(eFlagParsedIndex)) + { + s->Printf(" (CIE[%zu], FDE[%zu])\n", m_cie_map.size(), m_fde_map.size()); + s->IndentMore(); + cie_map_t::const_iterator cie_pos, cie_end = m_cie_map.end(); + const ArchSpec *arch = &m_objfile->GetModule()->GetArchitecture(); + + for (cie_pos = m_cie_map.begin(); cie_pos != cie_end; ++ cie_pos) + { + if (cie_pos->second.get() == NULL) + { + s->Indent(); + s->Printf("CIE{0x%8.8x} - unparsed\n", cie_pos->first); + } + else + { + cie_pos->second->Dump(s, thread, arch, m_reg_kind); + } + } + + fde_map_t::const_iterator fde_pos, fde_end = m_fde_map.end(); + for (fde_pos = m_fde_map.begin(); fde_pos != fde_end; ++ fde_pos) + { + if (fde_pos->second.fde_sp.get() == NULL) + { + s->Indent(); + s->Printf("FDE{0x%8.8x} - unparsed\n", fde_pos->second.fde_offset); + } + else + { + fde_pos->second.fde_sp->Dump(s, *this, thread); + } + } + s->IndentLess(); + } + else + { + s->PutCString(" (not indexed yet)\n"); + } +} + + +//uint32_t +//DWARFCallFrameInfo::UnwindThreadState(const Thread* currState, mapped_memory_t *memCache, bool is_first_frame, Thread* unwindState) +//{ +// if (currState == NULL || unwindState == NULL) +// return 0; +// +// *unwindState = *currState; +// uint32_t numRegisterUnwound = 0; +// uint64_t currPC = currState->GetPC(INVALID_VMADDR); +// +// if (currPC != INVALID_VMADDR) +// { +// // If this is not the first frame, we care about the previous instruction +// // since it will be at the instruction following the instruction that +// // made the function call. +// uint64_t unwindPC = currPC; +// if (unwindPC > 0 && !is_first_frame) +// --unwindPC; +// +//#if defined(__i386__) || defined(__x86_64__) +// // Only on i386 do we have __IMPORT segments that contain trampolines +// if (!currState->Is64Bit() && ImportRangesContainsAddress(unwindPC)) +// { +// uint64_t curr_sp = currState->GetSP(INVALID_VMADDR); +// mach_vm_address_t pc = INVALID_VMADDR; +// unwindState->SetSP(curr_sp + 4); +// kern_return_t err = mapped_memory_read_pointer(memCache, curr_sp, &pc); +// if (err == KERN_SUCCESS) +// { +// unwindState->SetPC(pc); +// return 2; +// } +// } +//#endif +// FDE *fde = FindFDE(unwindPC); +// if (fde) +// { +// FindRowUserData rowUserData (currState, unwindPC); +// ParseInstructions (currState, fde, FindRowForAddress, &rowUserData); +// +// const uint32_t numRegs = currState->NumRegisters(); +// for (uint32_t regNum = 0; regNum < numRegs; regNum++) +// { +// if (UnwindRegisterAtIndex(regNum, currState, &rowUserData.state, memCache, unwindState)) +// numRegisterUnwound++; +// } +// } +// } +// return numRegisterUnwound; +//} + + diff --git a/lldb/source/Symbol/Declaration.cpp b/lldb/source/Symbol/Declaration.cpp new file mode 100644 index 00000000000..a31a304b06f --- /dev/null +++ b/lldb/source/Symbol/Declaration.cpp @@ -0,0 +1,172 @@ +//===-- Declaration.cpp -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Symbol/Declaration.h" +#include "lldb/Core/Stream.h" + +using namespace lldb_private; + +Declaration::Declaration() : + m_file(), + m_line(0), + m_column(0) +{ +} + +Declaration::Declaration(const FileSpec& f, uint32_t l, uint32_t c) : + m_file(f), + m_line(l), + m_column(c) +{ +} + +Declaration::Declaration(const Declaration& rhs) : + m_file(rhs.m_file), + m_line(rhs.m_line), + m_column(rhs.m_column) +{ +} + +Declaration::Declaration(const Declaration* decl_ptr) : + m_file(), + m_line(0), + m_column(0) +{ + if (decl_ptr != NULL) + *this = *decl_ptr; +} + +bool +Declaration::IsValid() const +{ + return m_file && m_line != 0; +} + +void +Declaration::Clear() +{ + m_file.Clear(); + m_line= 0; + m_column = 0; +} + +void +Declaration::Dump(Stream *s) const +{ + if (m_file) + { + *s << ", decl = '" << m_file; + if (m_line > 0) + s->Printf(":%u", m_line); + if (m_column > 0) + s->Printf(":%u", m_column); + s->PutChar('\''); + } + else + { + if (m_line > 0) + { + s->Printf(", line = %u", m_line); + if (m_column > 0) + s->Printf(":%u", m_column); + } + else if (m_column > 0) + s->Printf(", column = %u", m_column); + } +} + +void +Declaration::DumpStopContext (Stream *s) const +{ + if (m_file) + { + if (s->GetVerbose()) + *s << m_file; + else + m_file.GetFilename().Dump(s); + + if (m_line > 0) + s->Printf(":%u", m_line); + if (m_column > 0) + s->Printf(":%u", m_column); + } + else + { + s->Printf(" line %u", m_line); + if (m_column > 0) + s->Printf(":%u", m_column); + } +} + +uint32_t +Declaration::GetColumn() const +{ + return m_column; +} + +FileSpec& +Declaration::GetFile() +{ + return m_file; +} + +const FileSpec& +Declaration::GetFile() const +{ + return m_file; +} + +uint32_t +Declaration::GetLine() const +{ + return m_line; +} + +size_t +Declaration::MemorySize() const +{ + return sizeof(Declaration); +} + +void +Declaration::SetColumn(uint32_t col) +{ + m_column = col; +} + +void +Declaration::SetFile(const FileSpec& file) +{ + m_file = file; +} + +void +Declaration::SetLine(uint32_t line) +{ + m_line = line; +} + + + +int +Declaration::Compare(const Declaration& a, const Declaration& b) +{ + int result = FileSpec::Compare(a.m_file, b.m_file, true); + if (result) + return result; + if (a.m_line < b.m_line) + return -1; + else if (a.m_line > b.m_line) + return 1; + if (a.m_column < b.m_column) + return -1; + else if (a.m_column > b.m_column) + return 1; + return 0; +} diff --git a/lldb/source/Symbol/Function.cpp b/lldb/source/Symbol/Function.cpp new file mode 100644 index 00000000000..51c449acd93 --- /dev/null +++ b/lldb/source/Symbol/Function.cpp @@ -0,0 +1,432 @@ +//===-- Function.cpp --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Symbol/Function.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/Section.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/LineTable.h" +#include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "clang/AST/Type.h" +#include "clang/AST/CanonicalType.h" + +using namespace lldb_private; + +//---------------------------------------------------------------------- +// Basic function information is contained in the FunctionInfo class. +// It is designed to contain the name, linkage name, and declaration +// location. +//---------------------------------------------------------------------- +FunctionInfo::FunctionInfo (const char *name, const Declaration *decl_ptr) : + m_name(name), + m_declaration(decl_ptr) +{ +} + + +FunctionInfo::FunctionInfo (const ConstString& name, const Declaration *decl_ptr) : + m_name(name), + m_declaration(decl_ptr) +{ +} + + +FunctionInfo::~FunctionInfo() +{ +} + +void +FunctionInfo::Dump(Stream *s) const +{ + if (m_name) + *s << ", name = \"" << m_name << "\""; + m_declaration.Dump(s); +} + + +int +FunctionInfo::Compare(const FunctionInfo& a, const FunctionInfo& b) +{ + int result = ConstString::Compare(a.GetName(), b.GetName()); + if (result) + return result; + + return Declaration::Compare(a.m_declaration, b.m_declaration); +} + + +Declaration& +FunctionInfo::GetDeclaration() +{ + return m_declaration; +} + +const Declaration& +FunctionInfo::GetDeclaration() const +{ + return m_declaration; +} + +const ConstString& +FunctionInfo::GetName() const +{ + return m_name; +} + +size_t +FunctionInfo::MemorySize() const +{ + return m_name.MemorySize() + m_declaration.MemorySize(); +} + + +InlineFunctionInfo::InlineFunctionInfo +( + const char *name, + const char *mangled, + const Declaration *decl_ptr, + const Declaration *call_decl_ptr +) : + FunctionInfo(name, decl_ptr), + m_mangled(mangled, true), + m_call_decl (call_decl_ptr) +{ +} + +InlineFunctionInfo::InlineFunctionInfo +( + const ConstString& name, + const Mangled &mangled, + const Declaration *decl_ptr, + const Declaration *call_decl_ptr +) : + FunctionInfo(name, decl_ptr), + m_mangled(mangled), + m_call_decl (call_decl_ptr) +{ +} + +InlineFunctionInfo::~InlineFunctionInfo() +{ +} + +int +InlineFunctionInfo::Compare(const InlineFunctionInfo& a, const InlineFunctionInfo& b) +{ + + int result = FunctionInfo::Compare(a, b); + if (result) + return result; + // only compare the mangled names if both have them + return Mangled::Compare(a.m_mangled, a.m_mangled); +} + +void +InlineFunctionInfo::Dump(Stream *s) const +{ + FunctionInfo::Dump(s); + if (m_mangled) + m_mangled.Dump(s); +} + +void +InlineFunctionInfo::DumpStopContext (Stream *s) const +{ +// s->Indent("[inlined] "); + s->Indent(); + if (m_mangled) + s->PutCString (m_mangled.GetName().AsCString()); + else + s->PutCString (m_name.AsCString()); +} + +Declaration & +InlineFunctionInfo::GetCallSite () +{ + return m_call_decl; +} + +const Declaration & +InlineFunctionInfo::GetCallSite () const +{ + return m_call_decl; +} + + +Mangled& +InlineFunctionInfo::GetMangled() +{ + return m_mangled; +} + +const Mangled& +InlineFunctionInfo::GetMangled() const +{ + return m_mangled; +} + +size_t +InlineFunctionInfo::MemorySize() const +{ + return FunctionInfo::MemorySize() + m_mangled.MemorySize(); +} + +//---------------------------------------------------------------------- +// +//---------------------------------------------------------------------- +Function::Function +( + CompileUnit *comp_unit, + lldb::user_id_t func_uid, + lldb::user_id_t type_uid, + const Mangled &mangled, + Type * type, + const AddressRange& range +) : + UserID(func_uid), + m_comp_unit(comp_unit), + m_type_uid(type_uid), + m_type(type), + m_mangled(mangled), + m_blocks(this, range), + m_frame_base(), + m_flags(), + m_prologue_byte_size(0) +{ + assert(comp_unit != NULL); +} + +Function::Function +( + CompileUnit *comp_unit, + lldb::user_id_t func_uid, + lldb::user_id_t type_uid, + const char *mangled, + Type *type, + const AddressRange &range +) : + UserID(func_uid), + m_comp_unit(comp_unit), + m_type_uid(type_uid), + m_type(type), + m_mangled(mangled, true), + m_blocks(this, range), + m_frame_base(), + m_flags(), + m_prologue_byte_size(0) +{ + assert(comp_unit != NULL); +} + + +Function::~Function() +{ +} + +const AddressRange & +Function::GetAddressRange() +{ + return GetBlocks(true).GetAddressRange(); +} + +BlockList & +Function::GetBlocks(bool can_create) +{ + if (m_blocks.IsEmpty() && can_create) + { + SymbolContext sc; + CalculateSymbolContext(&sc); + assert(sc.module_sp); + sc.module_sp->GetSymbolVendor()->ParseFunctionBlocks(sc); + } + return m_blocks; +} + +CompileUnit* +Function::GetCompileUnit() +{ + return m_comp_unit; +} + +const CompileUnit* +Function::GetCompileUnit() const +{ + return m_comp_unit; +} + +void +Function::Dump(Stream *s, bool show_context) const +{ + s->Printf("%.*p: ", (int)sizeof(void*) * 2, this); + s->Indent(); + *s << "Function" << (const UserID&)*this; + + m_mangled.Dump(s); + +// FunctionInfo::Dump(s); + if (m_type) + { + *s << ", type = " << (void*)m_type; + /// << " ("; + ///m_type->DumpTypeName(s); + ///s->PutChar(')'); + } + else if (m_type_uid != LLDB_INVALID_UID) + *s << ", type_uid = " << m_type_uid; + + s->EOL(); + // Dump the root object + if (!m_blocks.IsEmpty()) + m_blocks.Dump(s, Block::RootID, INT_MAX, show_context); +} + + +void +Function::CalculateSymbolContext(SymbolContext* sc) +{ + sc->function = this; + m_comp_unit->CalculateSymbolContext(sc); +} + +void +Function::DumpSymbolContext(Stream *s) +{ + m_comp_unit->DumpSymbolContext(s); + s->Printf(", Function{0x%8.8x}", GetID()); +} + +size_t +Function::MemorySize () const +{ + size_t mem_size = sizeof(Function) + m_blocks.MemorySize(); + return mem_size; +} + +Type* +Function::GetType() +{ + return m_type; +} + +const Type* +Function::GetType() const +{ + return m_type; +} + +Type +Function::GetReturnType () +{ + clang::QualType clang_type (clang::QualType::getFromOpaquePtr(GetType()->GetOpaqueClangQualType())); + assert (clang_type->isFunctionType()); + clang::FunctionType *function_type = dyn_cast<clang::FunctionType> (clang_type); + clang::QualType fun_return_qualtype = function_type->getResultType(); + + const ConstString fun_return_name(Type::GetClangTypeName(fun_return_qualtype.getAsOpaquePtr())); + + SymbolContext sc; + CalculateSymbolContext (&sc); + // Null out everything below the CompUnit 'cause we don't actually know these. + + size_t bit_size = ClangASTContext::GetTypeBitSize ((GetType()->GetClangASTContext().getASTContext()), &fun_return_qualtype); + Type return_type (0, GetType()->GetSymbolFile(), fun_return_name, bit_size, sc.comp_unit, 0, Type::eTypeUIDSynthetic, Declaration(), fun_return_qualtype.getAsOpaquePtr()); + return return_type; +} + +int +Function::GetArgumentCount () +{ + clang::QualType clang_type (clang::QualType::getFromOpaquePtr(GetType()->GetOpaqueClangQualType())); + assert (clang_type->isFunctionType()); + if (!clang_type->isFunctionProtoType()) + return -1; + + const clang::FunctionProtoType *function_proto_type = dyn_cast<clang::FunctionProtoType>(clang_type); + if (function_proto_type != NULL) + return function_proto_type->getNumArgs(); + + return 0; +} + +const Type +Function::GetArgumentTypeAtIndex (size_t idx) +{ + clang::QualType clang_type (clang::QualType::getFromOpaquePtr(GetType()->GetOpaqueClangQualType())); + assert (clang_type->isFunctionType()); + if (!clang_type->isFunctionProtoType()) + return Type(); + + const clang::FunctionProtoType *function_proto_type = dyn_cast<clang::FunctionProtoType>(clang_type); + if (function_proto_type != NULL) + { + unsigned num_args = function_proto_type->getNumArgs(); + if (idx >= num_args) + return Type(); + clang::QualType arg_qualtype = (function_proto_type->arg_type_begin())[idx]; + + const ConstString arg_return_name(Type::GetClangTypeName(arg_qualtype.getAsOpaquePtr())); + SymbolContext sc; + CalculateSymbolContext (&sc); + // Null out everything below the CompUnit 'cause we don't actually know these. + + size_t bit_size = ClangASTContext::GetTypeBitSize ((GetType()->GetClangASTContext().getASTContext()), &arg_qualtype); + Type arg_type (0, GetType()->GetSymbolFile(), arg_return_name, bit_size, sc.comp_unit, 0, Type::eTypeUIDSynthetic, Declaration(), arg_qualtype.getAsOpaquePtr()); + return arg_type; + } + + return Type(); +} + +const char * +Function::GetArgumentNameAtIndex (size_t idx) +{ + clang::Type *clang_type = static_cast<clang::QualType *>(GetType()->GetOpaqueClangQualType())->getTypePtr(); + assert (clang_type->isFunctionType()); + if (!clang_type->isFunctionProtoType()) + return NULL; + return NULL; +} + +bool +Function::IsVariadic () +{ + const clang::Type *clang_type = static_cast<clang::QualType *>(GetType()->GetOpaqueClangQualType())->getTypePtr(); + assert (clang_type->isFunctionType()); + if (!clang_type->isFunctionProtoType()) + return false; + + const clang::FunctionProtoType *function_proto_type = dyn_cast<clang::FunctionProtoType>(clang_type); + if (function_proto_type != NULL) + { + return function_proto_type->isVariadic(); + } + + return false; +} + +uint32_t +Function::GetPrologueByteSize () +{ + if (m_prologue_byte_size == 0 && m_flags.IsClear(flagsCalculatedPrologueSize)) + { + m_flags.Set(flagsCalculatedPrologueSize); + LineTable* line_table = m_comp_unit->GetLineTable (); + if (line_table) + { + LineEntry line_entry; + if (line_table->FindLineEntryByAddress(GetAddressRange().GetBaseAddress(), line_entry)) + m_prologue_byte_size = line_entry.range.GetByteSize(); + } + } + return m_prologue_byte_size; +} + + + diff --git a/lldb/source/Symbol/LineEntry.cpp b/lldb/source/Symbol/LineEntry.cpp new file mode 100644 index 00000000000..cdc3c54eaa3 --- /dev/null +++ b/lldb/source/Symbol/LineEntry.cpp @@ -0,0 +1,237 @@ +//===-- LineEntry.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Symbol/LineEntry.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Target/Process.h" + +using namespace lldb_private; + +LineEntry::LineEntry() : + range(), + file(), + line(0), + column(0), + is_start_of_statement(0), + is_start_of_basic_block(0), + is_terminal_entry(0), + is_prologue_end(0), + is_epilogue_begin(0) +{ +} + +LineEntry::LineEntry +( + lldb_private::Section *section, + lldb::addr_t section_offset, + lldb::addr_t byte_size, + const FileSpec &_file, + uint32_t _line, + uint16_t _column, + bool _is_start_of_statement, + bool _is_start_of_basic_block, + bool _is_prologue_end, + bool _is_epilogue_begin, + bool _is_terminal_entry +) : + range(section, section_offset, byte_size), + file(_file), + line(_line), + column(_column), + is_start_of_statement(_is_start_of_statement), + is_start_of_basic_block(_is_start_of_basic_block), + is_prologue_end(_is_prologue_end), + is_epilogue_begin(_is_epilogue_begin), + is_terminal_entry(_is_terminal_entry) +{ +} + +void +LineEntry::Clear() +{ + range.Clear(); + file.Clear(); + line = 0; + column = 0; + is_start_of_statement = 0; + is_start_of_basic_block = 0; + is_prologue_end = 0; + is_epilogue_begin = 0; + is_terminal_entry = 0; +} + + +bool +LineEntry::IsValid() const +{ + return range.GetBaseAddress().IsValid() && line != 0; +} + +bool +LineEntry::DumpStopContext(Stream *s) const +{ + bool result = false; + if (file) + { + file.Dump (s); + if (line) + s->PutChar(':'); + result = true; + } + if (line) + s->Printf ("%u", line); + else + result = false; + + return result; +} + +bool +LineEntry::Dump +( + Stream *s, + Process *process, + bool show_file, + Address::DumpStyle style, + Address::DumpStyle fallback_style, + bool show_range +) const +{ + if (show_range) + { + // Show address range + if (!range.Dump(s, process, style, fallback_style)) + return false; + } + else + { + // Show address only + if (!range.GetBaseAddress().Dump(s, + process, + style, + fallback_style)) + return false; + } + if (line) + s->Printf(", line = %u", line); + if (column) + s->Printf(", column = %u", column); + if (show_file) + { + *s << ", file = " << file; + } + if (is_start_of_statement) + *s << ", is_start_of_statement = TRUE"; + + if (is_start_of_basic_block) + *s << ", is_start_of_basic_block = TRUE"; + + if (is_prologue_end) + *s << ", is_prologue_end = TRUE"; + + if (is_epilogue_begin) + *s << ", is_epilogue_begin = TRUE"; + + if (is_terminal_entry) + *s << ", is_terminal_entry = TRUE"; + return true; +} + +bool +LineEntry::GetDescription (Stream *s, lldb::DescriptionLevel level, CompileUnit* cu, Process *process) const +{ + + if (level == lldb::eDescriptionLevelBrief || level == lldb::eDescriptionLevelFull) + { + // Show address only + range.GetBaseAddress().Dump(s, process, Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress); + + if (file) + *s << ' ' << file; + + if (line) + { + s->Printf(":%u", line); + if (column) + s->Printf(":%u", column); + } + + if (level == lldb::eDescriptionLevelFull) + { + if (is_start_of_statement) + *s << ", is_start_of_statement = TRUE"; + + if (is_start_of_basic_block) + *s << ", is_start_of_basic_block = TRUE"; + + if (is_prologue_end) + *s << ", is_prologue_end = TRUE"; + + if (is_epilogue_begin) + *s << ", is_epilogue_begin = TRUE"; + + if (is_terminal_entry) + *s << ", is_terminal_entry = TRUE"; + } + else + { + if (is_terminal_entry) + s->EOL(); + } + } + else + { + return Dump (s, process, true, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress, true); + } + return true; +} + + +bool +lldb_private::operator< (const LineEntry& a, const LineEntry& b) +{ + return LineEntry::Compare (a, b) < 0; +} + +int +LineEntry::Compare (const LineEntry& a, const LineEntry& b) +{ + int result = Address::CompareFileAddress (a.range.GetBaseAddress(), b.range.GetBaseAddress()); + if (result != 0) + return result; + + const lldb::addr_t a_byte_size = a.range.GetByteSize(); + const lldb::addr_t b_byte_size = b.range.GetByteSize(); + + if (a_byte_size < b_byte_size) + return -1; + if (a_byte_size > b_byte_size) + return +1; + + // Check for an end sequence entry mismatch after we have determined + // that the address values are equal. If one of the items is an end + // sequence, we don't care about the line, file, or column info. + if (a.is_terminal_entry > b.is_terminal_entry) + return -1; + if (a.is_terminal_entry < b.is_terminal_entry) + return +1; + + if (a.line < b.line) + return -1; + if (a.line > b.line) + return +1; + + if (a.column < b.column) + return -1; + if (a.column > b.column) + return +1; + + return FileSpec::Compare (a.file, b.file, true); +} + diff --git a/lldb/source/Symbol/LineTable.cpp b/lldb/source/Symbol/LineTable.cpp new file mode 100644 index 00000000000..326fd6e0e78 --- /dev/null +++ b/lldb/source/Symbol/LineTable.cpp @@ -0,0 +1,332 @@ +//===-- LineTable.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Core/Address.h" +#include "lldb/Core/Section.h" +#include "lldb/Core/Stream.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/LineTable.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// LineTable constructor +//---------------------------------------------------------------------- +LineTable::LineTable(CompileUnit* comp_unit) : + m_comp_unit(comp_unit), + m_section_list(), + m_entries() +{ +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +LineTable::~LineTable() +{ +} + +//void +//LineTable::AddLineEntry(const LineEntry& entry) +//{ +// // Do a binary search for the correct entry and insert it +// m_line_entries.insert(std::upper_bound(m_line_entries.begin(), m_line_entries.end(), entry), entry); +//} + +void +LineTable::AppendLineEntry +( + SectionSP& section_sp, + lldb::addr_t section_offset, + uint32_t line, + uint16_t column, + uint16_t file_idx, + bool is_start_of_statement, + bool is_start_of_basic_block, + bool is_prologue_end, + bool is_epilogue_begin, + bool is_terminal_entry +) +{ + uint32_t sect_idx = m_section_list.AddUniqueSection (section_sp); + // Make sure we don't user more than 256 sections as that is all we have + // room for in the LineTable::Entry::m_sect_idx. If this assert fires, + // we will need to m_sect_idx have more bits... + assert((section_offset & 0xffffffffff000000ull) == 0); + Entry entry(sect_idx, section_offset, line, column, file_idx, is_start_of_statement, is_start_of_basic_block, is_prologue_end, is_epilogue_begin, is_terminal_entry); + m_entries.push_back (entry); +} + + +void +LineTable::InsertLineEntry +( + SectionSP& section_sp, + lldb::addr_t section_offset, + uint32_t line, + uint16_t column, + uint16_t file_idx, + bool is_start_of_statement, + bool is_start_of_basic_block, + bool is_prologue_end, + bool is_epilogue_begin, + bool is_terminal_entry +) +{ + SectionSP line_section_sp(section_sp); + const Section *linked_section = line_section_sp->GetLinkedSection(); + if (linked_section) + { + section_offset += line_section_sp->GetLinkedOffset(); + line_section_sp = linked_section->GetSharedPointer(); + assert(line_section_sp.get()); + } + + uint32_t sect_idx = m_section_list.AddUniqueSection (line_section_sp); + // Make sure we don't user more than 256 sections as that is all we have + // room for in the LineTable::Entry::m_sect_idx. If this assert fires, + // we will need to m_sect_idx have more bits... + assert((section_offset & 0xffffffffff000000ull) == 0); + Entry entry(sect_idx, section_offset, line, column, file_idx, is_start_of_statement, is_start_of_basic_block, is_prologue_end, is_epilogue_begin, is_terminal_entry); + + entry_collection::iterator begin_pos = m_entries.begin(); + entry_collection::iterator end_pos = m_entries.end(); + LineTable::Entry::LessThanBinaryPredicate less_than_bp(this); + entry_collection::iterator pos = upper_bound(begin_pos, end_pos, entry, less_than_bp); + +// Stream s(stdout); +// s << "\n\nBefore:\n"; +// Dump (&s, Address::DumpStyleFileAddress); + m_entries.insert(pos, entry); +// s << "After:\n"; +// Dump (&s, Address::DumpStyleFileAddress); +} + +//---------------------------------------------------------------------- +LineTable::Entry::LessThanBinaryPredicate::LessThanBinaryPredicate(LineTable *line_table) : + m_line_table (line_table) +{ +} + +bool +LineTable::Entry::LessThanBinaryPredicate::operator() (const LineTable::Entry& a, const LineTable::Entry& b) const +{ + if (a.sect_idx == b.sect_idx) + { + #define LT_COMPARE(a,b) if (a != b) return a < b + LT_COMPARE (a.sect_offset, b.sect_offset); + LT_COMPARE (a.line, b.line); + LT_COMPARE (a.column, b.column); + LT_COMPARE (a.is_start_of_statement, b.is_start_of_statement); + LT_COMPARE (a.is_start_of_basic_block, b.is_start_of_basic_block); + // b and a reversed on purpose below. + LT_COMPARE (b.is_prologue_end, a.is_prologue_end); + LT_COMPARE (a.is_epilogue_begin, b.is_epilogue_begin); + // b and a reversed on purpose below. + LT_COMPARE (b.is_terminal_entry, a.is_terminal_entry); + LT_COMPARE (a.file_idx, b.file_idx); + return false; + #undef LT_COMPARE; + } + + const Section *a_section = m_line_table->GetSectionForEntryIndex (a.sect_idx); + const Section *b_section = m_line_table->GetSectionForEntryIndex (b.sect_idx); + return Section::Compare(*a_section, *b_section) < 0; +}; + + +Section * +LineTable::GetSectionForEntryIndex (uint32_t idx) +{ + if (idx < m_section_list.GetSize()) + return m_section_list.GetSectionAtIndex(idx).get(); + return NULL; +} + +uint32_t +LineTable::GetSize() const +{ + return m_entries.size(); +} + +bool +LineTable::GetLineEntryAtIndex(uint32_t idx, LineEntry& line_entry) +{ + if (idx < m_entries.size()) + { + ConvertEntryAtIndexToLineEntry (idx, line_entry); + return true; + } + line_entry.Clear(); + return false; +} + +bool +LineTable::FindLineEntryByAddress (const Address &so_addr, LineEntry& line_entry, uint32_t *index_ptr) +{ + if (index_ptr != NULL ) + *index_ptr = UINT32_MAX; + + bool success = false; + uint32_t sect_idx = m_section_list.FindSectionIndex (so_addr.GetSection()); + if (sect_idx != UINT32_MAX) + { + Entry search_entry; + search_entry.sect_idx = sect_idx; + search_entry.sect_offset = so_addr.GetOffset(); + + entry_collection::const_iterator begin_pos = m_entries.begin(); + entry_collection::const_iterator end_pos = m_entries.end(); + entry_collection::const_iterator pos = lower_bound(begin_pos, end_pos, search_entry, Entry::EntryAddressLessThan); + if (pos != end_pos) + { + if (pos != begin_pos) + { + if (pos->sect_offset != search_entry.sect_offset) + --pos; + else if (pos->sect_offset == search_entry.sect_offset) + { + while (pos != begin_pos) + { + entry_collection::const_iterator prev_pos = pos - 1; + if (prev_pos->sect_idx == search_entry.sect_idx && + prev_pos->sect_offset == search_entry.sect_offset) + --pos; + else + break; + } + } + + } + uint32_t match_idx = std::distance (begin_pos, pos); + success = ConvertEntryAtIndexToLineEntry(match_idx, line_entry); + if (index_ptr != NULL && success) + *index_ptr = match_idx; + } + } + return success; +} + + +bool +LineTable::ConvertEntryAtIndexToLineEntry (uint32_t idx, LineEntry &line_entry) +{ + if (idx < m_entries.size()) + { + const Entry& entry = m_entries[idx]; + line_entry.range.GetBaseAddress().SetSection(m_section_list.GetSectionAtIndex (entry.sect_idx).get()); + line_entry.range.GetBaseAddress().SetOffset(entry.sect_offset); + if (!entry.is_terminal_entry && idx + 1 < m_entries.size()) + { + const Entry& next_entry = m_entries[idx+1]; + if (next_entry.sect_idx == entry.sect_idx) + { + line_entry.range.SetByteSize(next_entry.sect_offset - entry.sect_offset); + } + else + { + Address next_line_addr(m_section_list.GetSectionAtIndex (next_entry.sect_idx).get(), next_entry.sect_offset); + line_entry.range.SetByteSize(next_line_addr.GetFileAddress() - line_entry.range.GetBaseAddress().GetFileAddress()); + } + } + else + line_entry.range.SetByteSize(0); + line_entry.file = m_comp_unit->GetSupportFiles().GetFileSpecAtIndex (entry.file_idx); + line_entry.line = entry.line; + line_entry.column = entry.column; + line_entry.is_start_of_statement = entry.is_start_of_statement; + line_entry.is_start_of_basic_block = entry.is_start_of_basic_block; + line_entry.is_prologue_end = entry.is_prologue_end; + line_entry.is_epilogue_begin = entry.is_epilogue_begin; + line_entry.is_terminal_entry = entry.is_terminal_entry; + return true; + } + return false; +} + +uint32_t +LineTable::FindLineEntryIndexByFileIndex (uint32_t start_idx, uint32_t file_idx, uint32_t line, bool exact, LineEntry* line_entry_ptr) +{ + const size_t count = m_entries.size(); + size_t best_match = UINT_MAX; + + for (size_t idx = start_idx; idx < count; ++idx) + { + // Skip line table rows that terminate the previous row (is_terminal_entry is non-zero) + if (m_entries[idx].is_terminal_entry) + continue; + + if (m_entries[idx].file_idx != file_idx) + continue; + + // Exact match always wins. Otherwise try to find the closest line > the desired + // line. + // FIXME: Maybe want to find the line closest before and the line closest after and + // if they're not in the same function, don't return a match. + + if (m_entries[idx].line < line) + { + continue; + } + else if (m_entries[idx].line == line) + { + if (line_entry_ptr) + ConvertEntryAtIndexToLineEntry (idx, *line_entry_ptr); + return idx; + } + else if (!exact) + { + if (best_match == UINT32_MAX) + best_match = idx; + else if (m_entries[idx].line < m_entries[best_match].line) + best_match = idx; + } + } + + if (best_match != UINT_MAX) + { + if (line_entry_ptr) + ConvertEntryAtIndexToLineEntry (best_match, *line_entry_ptr); + return best_match; + } + return UINT_MAX; +} + +void +LineTable::Dump (Stream *s, Process *process, Address::DumpStyle style, Address::DumpStyle fallback_style, bool show_line_ranges) +{ + const size_t count = m_entries.size(); + LineEntry line_entry; + FileSpec prev_file; + for (size_t idx = 0; idx < count; ++idx) + { + ConvertEntryAtIndexToLineEntry (idx, line_entry); + line_entry.Dump (s, process, prev_file != line_entry.file, style, fallback_style, show_line_ranges); + s->EOL(); + prev_file = line_entry.file; + } +} + + +void +LineTable::GetDescription (Stream *s, Process *process, DescriptionLevel level) +{ + const size_t count = m_entries.size(); + LineEntry line_entry; + for (size_t idx = 0; idx < count; ++idx) + { + ConvertEntryAtIndexToLineEntry (idx, line_entry); + line_entry.GetDescription (s, level, m_comp_unit, process); + s->EOL(); + } +} + + + diff --git a/lldb/source/Symbol/ObjectFile.cpp b/lldb/source/Symbol/ObjectFile.cpp new file mode 100644 index 00000000000..8d224488641 --- /dev/null +++ b/lldb/source/Symbol/ObjectFile.cpp @@ -0,0 +1,92 @@ +//===-- ObjectFile.cpp ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/lldb-private.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/RegularExpression.h" +#include "lldb/Core/Timer.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/ObjectContainer.h" +#include "lldb/Symbol/SymbolFile.h" + +using namespace lldb; +using namespace lldb_private; + +ObjectFile* +ObjectFile::FindPlugin (Module* module, const FileSpec* file, lldb::addr_t file_offset, lldb::addr_t file_size) +{ + Timer scoped_timer (__PRETTY_FUNCTION__, + "ObjectFile::FindPlugin (module = %s/%s, file = %p, file_offset = 0x%z8.8x, file_size = 0x%z8.8x)", + module->GetFileSpec().GetDirectory().AsCString(), + module->GetFileSpec().GetFilename().AsCString(), + file, file_offset, file_size); + std::auto_ptr<ObjectFile> object_file_ap; + + if (module != NULL) + { + if (file) + { + if (file_size == 0) + file_size = file->GetByteSize(); + + if (file_size == 0) + { + // Check for archive file with format "/path/to/archive.a(object.o)" + char path_with_object[PATH_MAX*2]; + module->GetFileSpec().GetPath(path_with_object, sizeof(path_with_object)); + + RegularExpression g_object_regex("(.*)\\(([^\\)]+)\\)$"); + if (g_object_regex.Execute (path_with_object, 2)) + { + FileSpec archive_file; + std::string path; + std::string object; + if (g_object_regex.GetMatchAtIndex (path_with_object, 1, path) && + g_object_regex.GetMatchAtIndex (path_with_object, 2, object)) + { + archive_file.SetFile (path.c_str()); + file_size = archive_file.GetByteSize(); + if (file_size > 0) + module->SetFileSpecAndObjectName (archive_file, ConstString(object.c_str())); + } + } + } + + DataBufferSP file_header_data_sp(file->ReadFileContents(file_offset, 512)); + uint32_t idx; + + // Check if this is a normal object file by iterating through + // all object file plugin instances. + ObjectFileCreateInstance create_object_file_callback; + for (idx = 0; (create_object_file_callback = PluginManager::GetObjectFileCreateCallbackAtIndex(idx)) != NULL; ++idx) + { + object_file_ap.reset (create_object_file_callback(module, file_header_data_sp, file, file_offset, file_size)); + if (object_file_ap.get()) + return object_file_ap.release(); + } + + // Check if this is a object container by iterating through + // all object container plugin instances and then trying to get + // an object file from the container. + ObjectContainerCreateInstance create_object_container_callback; + for (idx = 0; (create_object_container_callback = PluginManager::GetObjectContainerCreateCallbackAtIndex(idx)) != NULL; ++idx) + { + std::auto_ptr<ObjectContainer> object_container_ap(create_object_container_callback(module, file_header_data_sp, file, file_offset, file_size)); + + if (object_container_ap.get()) + object_file_ap.reset (object_container_ap->GetObjectFile(file)); + + if (object_file_ap.get()) + return object_file_ap.release(); + } + } + } + return NULL; +} diff --git a/lldb/source/Symbol/Symbol.cpp b/lldb/source/Symbol/Symbol.cpp new file mode 100644 index 00000000000..fb01fc176bd --- /dev/null +++ b/lldb/source/Symbol/Symbol.cpp @@ -0,0 +1,463 @@ +//===-- Symbol.cpp ----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Symbol/Symbol.h" + +#include "lldb/Core/Module.h" +#include "lldb/Core/Section.h" +#include "lldb/Core/Stream.h" +#include "lldb/Target/Process.h" + +using namespace lldb; +using namespace lldb_private; + + +Symbol::Symbol() : + UserID (), + m_mangled (), + m_type (eSymbolTypeInvalid), + m_type_data (0), + m_type_data_resolved (false), + m_is_synthetic (false), + m_is_debug (false), + m_is_external (false), + m_size_is_sibling (false), + m_size_is_synthesized (false), + m_searched_for_function (false), + m_addr_range (), + m_flags (), + m_function (NULL) +{ +} + +Symbol::Symbol +( + user_id_t symID, + const char *name, + bool name_is_mangled, + SymbolType type, + bool external, + bool is_debug, + bool is_trampoline, + bool is_artificial, + const Section* section, + addr_t offset, + uint32_t size, + uint32_t flags +) : + UserID (symID), + m_mangled (name, name_is_mangled), + m_type (type), + m_type_data (0), + m_type_data_resolved (false), + m_is_synthetic (is_artificial), + m_is_debug (is_debug), + m_is_external (external), + m_size_is_sibling (false), + m_size_is_synthesized (false), + m_searched_for_function (false), + m_addr_range (section, offset, size), + m_flags (flags), + m_function (NULL) +{ +} + +Symbol::Symbol +( + user_id_t symID, + const char *name, + bool name_is_mangled, + SymbolType type, + bool external, + bool is_debug, + bool is_trampoline, + bool is_artificial, + const AddressRange &range, + uint32_t flags +) : + UserID (symID), + m_mangled (name, name_is_mangled), + m_type (type), + m_type_data (0), + m_type_data_resolved (false), + m_is_synthetic (is_artificial), + m_is_debug (is_debug), + m_is_external (external), + m_size_is_sibling (false), + m_size_is_synthesized (false), + m_searched_for_function (false), + m_addr_range (range), + m_flags (flags), + m_function (NULL) +{ +} + +Symbol::Symbol(const Symbol& rhs): + UserID (rhs), + m_mangled (rhs.m_mangled), + m_type (rhs.m_type), + m_type_data (rhs.m_type_data), + m_type_data_resolved (rhs.m_type_data_resolved), + m_is_synthetic (rhs.m_is_synthetic), + m_is_debug (rhs.m_is_debug), + m_is_external (rhs.m_is_external), + m_size_is_sibling (rhs.m_size_is_sibling), + m_size_is_synthesized (false), + m_searched_for_function (false), + m_addr_range (rhs.m_addr_range), + m_flags (rhs.m_flags), + m_function (NULL) +{ +} + +const Symbol& +Symbol::operator= (const Symbol& rhs) +{ + if (this != &rhs) + { + UserID::operator= (rhs); + m_mangled = rhs.m_mangled; + m_type = rhs.m_type; + m_type_data = rhs.m_type_data; + m_type_data_resolved = rhs.m_type_data_resolved; + m_is_synthetic = rhs.m_is_synthetic; + m_is_debug = rhs.m_is_debug; + m_is_external = rhs.m_is_external; + m_size_is_sibling = rhs.m_size_is_sibling; + m_size_is_synthesized = rhs.m_size_is_sibling; + m_searched_for_function = rhs.m_searched_for_function; + m_addr_range = rhs.m_addr_range; + m_flags = rhs.m_flags; + m_function = rhs.m_function; + } + return *this; +} + +AddressRange & +Symbol::GetAddressRangeRef() +{ + return m_addr_range; +} + +const AddressRange & +Symbol::GetAddressRangeRef() const +{ + return m_addr_range; +} + +AddressRange * +Symbol::GetAddressRangePtr() +{ + if (m_addr_range.GetBaseAddress().GetSection()) + return &m_addr_range; + return NULL; +} + +const AddressRange * +Symbol::GetAddressRangePtr() const +{ + if (m_addr_range.GetBaseAddress().GetSection()) + return &m_addr_range; + return NULL; +} + +bool +Symbol::GetSizeIsSibling() const +{ + return m_size_is_sibling; +} + +bool +Symbol::GetSizeIsSynthesized() const +{ + return m_size_is_synthesized; +} + +uint32_t +Symbol::GetSiblingIndex() const +{ + return m_size_is_sibling ? m_addr_range.GetByteSize() : 0; +} + +uint32_t +Symbol::GetFlags() const +{ + return m_flags; +} + +void +Symbol::SetFlags (uint32_t flags) +{ + m_flags = flags; +} + +SymbolType +Symbol::GetType() const +{ + return m_type; +} + +void +Symbol::SetType(SymbolType type) +{ + m_type = type; +} + +bool +Symbol::IsSynthetic () const +{ + return m_is_synthetic; +} + +void +Symbol::SetIsSynthetic (bool b) +{ + m_is_synthetic = b; +} + +void +Symbol::SetSizeIsSynthesized(bool b) +{ + m_size_is_synthesized = b; +} + + +bool +Symbol::IsDebug() const +{ + return m_is_debug; +} + +void +Symbol::SetDebug (bool b) +{ + m_is_debug = b; +} + +bool +Symbol::IsExternal() const +{ + return m_is_external; +} + +void +Symbol::SetExternal(bool b) +{ + m_is_external = b; +} + +bool +Symbol::IsTrampoline () const +{ + return m_type == eSymbolTypeTrampoline; +} + +uint32_t +Symbol::GetByteSize() const +{ + return m_addr_range.GetByteSize(); +} + +void +Symbol::SetByteSize (uint32_t size) +{ + m_addr_range.SetByteSize(size); +} + +void +Symbol::SetSizeIsSibling (bool b) +{ + m_size_is_sibling = b; +} + +void +Symbol::Dump(Stream *s, Process *process, uint32_t index) const +{ +// s->Printf("%.*p: ", (int)sizeof(void*) * 2, this); +// s->Indent(); +// s->Printf("Symbol[%5u] %6u %c%c %-12s ", + s->Printf("[%5u] %6u %c%c%c %-12s ", + index, + GetID(), + m_is_debug ? 'D' : ' ', + m_is_synthetic ? 'S' : ' ', + m_is_external ? 'X' : ' ', + GetTypeAsString()); + + const Section *section = m_addr_range.GetBaseAddress().GetSection(); + if (section != NULL) + { + if (!m_addr_range.GetBaseAddress().Dump(s, NULL, Address::DumpStyleFileAddress)) + s->Printf("%*s", 18, ""); + + s->PutChar(' '); + + if (!m_addr_range.GetBaseAddress().Dump(s, process, Address::DumpStyleLoadAddress)) + s->Printf("%*s", 18, ""); + + const char *format = m_size_is_sibling ? + " Sibling -> [%5llu] 0x%8.8x %s\n": + " 0x%16.16llx 0x%8.8x %s\n"; + s->Printf( format, + m_addr_range.GetByteSize(), + m_flags, + m_mangled.GetName().AsCString("")); + } + else + { + const char *format = m_size_is_sibling ? + "0x%16.16llx Sibling -> [%5llu] 0x%8.8x %s\n": + "0x%16.16llx 0x%16.16llx 0x%8.8x %s\n"; + s->Printf( format, + m_addr_range.GetBaseAddress().GetOffset(), + m_addr_range.GetByteSize(), + m_flags, + m_mangled.GetName().AsCString("")); + } +} + +const Mangled& +Symbol::GetMangled() const +{ + return m_mangled; +} + +Mangled& +Symbol::GetMangled() +{ + return m_mangled; +} + +Address & +Symbol::GetValue() +{ + return m_addr_range.GetBaseAddress(); +} + +const Address & +Symbol::GetValue() const +{ + return m_addr_range.GetBaseAddress(); +} + +void +Symbol::SetValue (Address &value) +{ + m_addr_range.GetBaseAddress() = value; +} + +Function * +Symbol::GetFunction () +{ + if (m_function == NULL && !m_searched_for_function) + { + m_searched_for_function = true; + Module *module = m_addr_range.GetBaseAddress().GetModule(); + if (module) + { + SymbolContext sc; + if (module->ResolveSymbolContextForAddress(m_addr_range.GetBaseAddress(), eSymbolContextFunction, sc)) + m_function = sc.function; + } + } + return m_function; +} + +uint32_t +Symbol::GetPrologueByteSize () +{ + if (m_type == eSymbolTypeCode || m_type == eSymbolTypeFunction) + { + if (!m_type_data_resolved) + { + m_type_data_resolved = true; + Module *module = m_addr_range.GetBaseAddress().GetModule(); + SymbolContext sc; + if (module && module->ResolveSymbolContextForAddress (m_addr_range.GetBaseAddress(), + eSymbolContextLineEntry, + sc)) + { + m_type_data = sc.line_entry.range.GetByteSize(); + } + else + { + // TODO: expose something in Process to figure out the + // size of a function prologue. + } + } + return m_type_data; + } + return 0; +} + +void +Symbol::SetValue (const AddressRange &range) +{ + m_addr_range = range; +} + + +void +Symbol::SetValue(addr_t value) +{ + m_addr_range.GetBaseAddress().SetSection(NULL); + m_addr_range.GetBaseAddress().SetOffset(value); +} + + +bool +Symbol::Compare(const ConstString& name, SymbolType type) const +{ + if (m_type == eSymbolTypeAny || m_type == type) + return m_mangled.GetMangledName() == name || m_mangled.GetDemangledName() == name; + return false; +} + +#define ENUM_TO_CSTRING(x) case eSymbolType##x: return #x; + +const char * +Symbol::GetTypeAsString() const +{ + switch (m_type) + { + ENUM_TO_CSTRING(Invalid); + ENUM_TO_CSTRING(Absolute); + ENUM_TO_CSTRING(Extern); + ENUM_TO_CSTRING(Code); + ENUM_TO_CSTRING(Data); + ENUM_TO_CSTRING(Trampoline); + ENUM_TO_CSTRING(Runtime); + ENUM_TO_CSTRING(Exception); + ENUM_TO_CSTRING(SourceFile); + ENUM_TO_CSTRING(HeaderFile); + ENUM_TO_CSTRING(ObjectFile); + ENUM_TO_CSTRING(Function); + ENUM_TO_CSTRING(FunctionEnd); + ENUM_TO_CSTRING(CommonBlock); + ENUM_TO_CSTRING(Block); + ENUM_TO_CSTRING(Static); + ENUM_TO_CSTRING(Global); + ENUM_TO_CSTRING(Local); + ENUM_TO_CSTRING(Param); + ENUM_TO_CSTRING(Variable); + ENUM_TO_CSTRING(VariableType); + ENUM_TO_CSTRING(LineEntry); + ENUM_TO_CSTRING(LineHeader); + ENUM_TO_CSTRING(ScopeBegin); + ENUM_TO_CSTRING(ScopeEnd); + ENUM_TO_CSTRING(Additional); + ENUM_TO_CSTRING(Compiler); + ENUM_TO_CSTRING(Instrumentation); + ENUM_TO_CSTRING(Undefined); + default: + break; + } + return "<unknown SymbolType>"; +} + diff --git a/lldb/source/Symbol/SymbolContext.cpp b/lldb/source/Symbol/SymbolContext.cpp new file mode 100644 index 00000000000..0a33d5adbf0 --- /dev/null +++ b/lldb/source/Symbol/SymbolContext.cpp @@ -0,0 +1,424 @@ +//===-- SymbolContext.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Core/Module.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/Symbol.h" +#include "lldb/Target/Target.h" +#include "lldb/Symbol/SymbolVendor.h" + +using namespace lldb; +using namespace lldb_private; + +SymbolContext::SymbolContext() : + target_sp (), + module_sp (), + comp_unit (NULL), + function (NULL), + block (NULL), + line_entry (), + symbol (NULL) +{ +} + +SymbolContext::SymbolContext(const ModuleSP& m, CompileUnit *cu, Function *f, Block *b, LineEntry *le, Symbol *s) : + target_sp (), + module_sp (m), + comp_unit (cu), + function (f), + block (b), + line_entry (), + symbol (s) +{ + if (le) + line_entry = *le; +} + +SymbolContext::SymbolContext(const TargetSP &t, const ModuleSP& m, CompileUnit *cu, Function *f, Block *b, LineEntry *le, Symbol *s) : + target_sp (t), + module_sp (m), + comp_unit (cu), + function (f), + block (b), + line_entry (), + symbol (s) +{ + if (le) + line_entry = *le; +} + +SymbolContext::SymbolContext(const SymbolContext& rhs) : + target_sp (rhs.target_sp), + module_sp (rhs.module_sp), + comp_unit (rhs.comp_unit), + function (rhs.function), + block (rhs.block), + line_entry (rhs.line_entry), + symbol (rhs.symbol) +{ +} + + +SymbolContext::SymbolContext (SymbolContextScope *sc_scope) : + target_sp (), + module_sp (), + comp_unit (NULL), + function (NULL), + block (NULL), + line_entry (), + symbol (NULL) +{ + sc_scope->CalculateSymbolContext (this); +} + +const SymbolContext& +SymbolContext::operator= (const SymbolContext& rhs) +{ + if (this != &rhs) + { + target_sp = rhs.target_sp; + module_sp = rhs.module_sp; + comp_unit = rhs.comp_unit; + function = rhs.function; + block = rhs.block; + line_entry = rhs.line_entry; + symbol = rhs.symbol; + } + return *this; +} + +void +SymbolContext::Clear() +{ + target_sp.reset(); + module_sp.reset(); + comp_unit = NULL; + function = NULL; + block = NULL; + line_entry.Clear(); + symbol = NULL; +} + +void +SymbolContext::DumpStopContext +( + Stream *s, + ExecutionContextScope *exe_scope, + const Address &addr, + bool show_module +) const +{ + Process *process = NULL; + if (exe_scope) + process = exe_scope->CalculateProcess(); + addr_t load_addr = addr.GetLoadAddress (process); + + if (show_module && module_sp) + { + *s << module_sp->GetFileSpec().GetFilename() << '`'; + } + + if (function != NULL) + { + if (function->GetMangled().GetName()) + function->GetMangled().GetName().Dump(s); + + const addr_t func_load_addr = function->GetAddressRange().GetBaseAddress().GetLoadAddress(process); + if (load_addr > func_load_addr) + s->Printf(" + %llu", load_addr - func_load_addr); + + if (block != NULL) + { + s->IndentMore(); + block->DumpStopContext(s, this); + s->IndentLess(); + } + else + { + if (line_entry.IsValid()) + { + s->PutCString(" at "); + if (line_entry.DumpStopContext(s)) + return; + } + } + } + else if (symbol != NULL) + { + symbol->GetMangled().GetName().Dump(s); + + if (symbol->GetAddressRangePtr()) + { + const addr_t sym_load_addr = symbol->GetAddressRangePtr()->GetBaseAddress().GetLoadAddress(process); + if (load_addr > sym_load_addr) + s->Printf(" + %llu", load_addr - sym_load_addr); + } + } + else + { + addr.Dump(s, exe_scope, Address::DumpStyleModuleWithFileAddress); + } +} + +void +SymbolContext::Dump(Stream *s, Process *process) const +{ + *s << (void *)this << ": "; + s->Indent(); + s->PutCString("SymbolContext"); + s->IndentMore(); + s->EOL(); + s->IndentMore(); + s->Indent(); + *s << "Module = " << (void *)module_sp.get() << ' '; + if (module_sp) + module_sp->GetFileSpec().Dump(s); + s->EOL(); + s->Indent(); + *s << "CompileUnit = " << (void *)comp_unit; + if (comp_unit != NULL) + *s << " {" << comp_unit->GetID() << "} " << *(dynamic_cast<FileSpec*> (comp_unit)); + s->EOL(); + s->Indent(); + *s << "Function = " << (void *)function; + if (function != NULL) + { + *s << " {" << function->GetID() << "} ";/// << function->GetType()->GetName(); +// Type* func_type = function->Type(); +// if (func_type) +// { +// s->EOL(); +// const UserDefType* func_udt = func_type->GetUserDefinedType().get(); +// if (func_udt) +// { +// s->IndentMore(); +// func_udt->Dump(s, func_type); +// s->IndentLess(); +// } +// } + } + s->EOL(); + s->Indent(); + *s << "Block = " << (void *)block; + if (block != NULL) + *s << " {" << block->GetID() << '}'; + // Dump the block and pass it a negative depth to we print all the parent blocks + //if (block != NULL) + // block->Dump(s, function->GetFileAddress(), INT_MIN); + s->EOL(); + s->Indent(); + *s << "LineEntry = "; + line_entry.Dump (s, process, true, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress, true); + s->EOL(); + s->Indent(); + *s << "Symbol = " << (void *)symbol; + if (symbol != NULL && symbol->GetMangled()) + *s << ' ' << symbol->GetMangled().GetName().AsCString(); + s->EOL(); + s->IndentLess(); + s->IndentLess(); +} + +bool +lldb_private::operator== (const SymbolContext& lhs, const SymbolContext& rhs) +{ + return lhs.target_sp.get() == rhs.target_sp.get() && + lhs.module_sp.get() == rhs.module_sp.get() && + lhs.comp_unit == rhs.comp_unit && + lhs.function == rhs.function && + LineEntry::Compare(lhs.line_entry, rhs.line_entry) == 0 && + lhs.symbol == rhs.symbol; +} + +bool +lldb_private::operator!= (const SymbolContext& lhs, const SymbolContext& rhs) +{ + return lhs.target_sp.get() != rhs.target_sp.get() || + lhs.module_sp.get() != rhs.module_sp.get() || + lhs.comp_unit != rhs.comp_unit || + lhs.function != rhs.function || + LineEntry::Compare(lhs.line_entry, rhs.line_entry) != 0 || + lhs.symbol != rhs.symbol; +} + +bool +SymbolContext::GetAddressRange (uint32_t scope, AddressRange &range) const +{ + if ((scope & eSymbolContextLineEntry) && line_entry.IsValid()) + { + range = line_entry.range; + return true; + } + else if ((scope & eSymbolContextFunction) && function != NULL) + { + range = function->GetAddressRange(); + return true; + } + else if ((scope & eSymbolContextSymbol) && symbol != NULL && symbol->GetAddressRangePtr()) + { + range = *symbol->GetAddressRangePtr(); + + if (range.GetByteSize() == 0) + { + if (module_sp) + { + ObjectFile *objfile = module_sp->GetObjectFile(); + if (objfile) + { + Symtab *symtab = objfile->GetSymtab(); + if (symtab) + range.SetByteSize(symtab->CalculateSymbolSize (symbol)); + } + } + } + return true; + } + range.Clear(); + return false; +} + + +Function * +SymbolContext::FindFunctionByName (const char *name) const +{ + ConstString name_const_str (name); + if (function != NULL) + { + // FIXME: Look in the class of the current function, if it exists, + // for methods matching name. + } + + // + if (comp_unit != NULL) + { + // Make sure we've read in all the functions. We should be able to check and see + // if there's one by this name present before we do this... + module_sp->GetSymbolVendor()->ParseCompileUnitFunctions(*this); + uint32_t func_idx; + lldb::FunctionSP func_sp; + for (func_idx = 0; (func_sp = comp_unit->GetFunctionAtIndex(func_idx)) != NULL; ++func_idx) + { + if (func_sp->GetMangled().GetName() == name_const_str) + return func_sp.get(); + } + } + if (module_sp != NULL) + { + SymbolContextList sc_matches; + if (module_sp->FindFunctions (name_const_str, false, sc_matches) > 0) + { + SymbolContext sc; + sc_matches.GetContextAtIndex (0, sc); + return sc.function; + } + } + + if (target_sp) + { + SymbolContextList sc_matches; + if (target_sp->GetImages().FindFunctions (name_const_str, sc_matches) > 0) + { + SymbolContext sc; + sc_matches.GetContextAtIndex (0, sc); + return sc.function; + } + } + + return NULL; +} + +lldb::VariableSP +SymbolContext::FindVariableByName (const char *name) const +{ + lldb::VariableSP return_value; + return return_value; +} + +lldb::TypeSP +SymbolContext::FindTypeByName (const char *name) const +{ + lldb::TypeSP return_value; + return return_value; +} + +//---------------------------------------------------------------------- +// +// SymbolContextList +// +//---------------------------------------------------------------------- + + +SymbolContextList::SymbolContextList() : + m_symbol_contexts() +{ +} + +SymbolContextList::~SymbolContextList() +{ +} + +void +SymbolContextList::Append(const SymbolContext& sc) +{ + m_symbol_contexts.push_back(sc); +} + +void +SymbolContextList::Clear() +{ + m_symbol_contexts.clear(); +} + +void +SymbolContextList::Dump(Stream *s, Process *process) const +{ + + *s << (void *)this << ": "; + s->Indent(); + s->PutCString("SymbolContextList"); + s->EOL(); + s->IndentMore(); + + collection::const_iterator pos, end = m_symbol_contexts.end(); + for (pos = m_symbol_contexts.begin(); pos != end; ++pos) + { + pos->Dump(s, process); + } + s->IndentLess(); +} + +bool +SymbolContextList::GetContextAtIndex(uint32_t idx, SymbolContext& sc) const +{ + if (idx < m_symbol_contexts.size()) + { + sc = m_symbol_contexts[idx]; + return true; + } + return false; +} + +bool +SymbolContextList::RemoveContextAtIndex (uint32_t idx) +{ + if (idx < m_symbol_contexts.size()) + { + m_symbol_contexts.erase(m_symbol_contexts.begin() + idx); + return true; + } + return false; +} + +uint32_t +SymbolContextList::GetSize() const +{ + return m_symbol_contexts.size(); +} diff --git a/lldb/source/Symbol/SymbolFile.cpp b/lldb/source/Symbol/SymbolFile.cpp new file mode 100644 index 00000000000..edfd56d3bd9 --- /dev/null +++ b/lldb/source/Symbol/SymbolFile.cpp @@ -0,0 +1,50 @@ +//===-- SymbolFile.cpp ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/lldb-private.h" +#include "lldb/Symbol/SymbolFile.h" +#include "lldb/Core/PluginManager.h" + +using namespace lldb_private; + +SymbolFile* +SymbolFile::FindPlugin (ObjectFile* obj_file) +{ + std::auto_ptr<SymbolFile> best_sym_file_ap; + if (obj_file != NULL) + { + // TODO: Load any plug-ins in the appropriate plug-in search paths and + // iterate over all of them to find the best one for the job. + + //---------------------------------------------------------------------- + // We currently only have one debug symbol parser... + //---------------------------------------------------------------------- + std::auto_ptr<SymbolFile> best_symfile_ap; + uint32_t best_symfile_abilities = 0; + + SymbolFileCreateInstance create_callback; + for (uint32_t idx = 0; (create_callback = PluginManager::GetSymbolFileCreateCallbackAtIndex(idx)) != NULL; ++idx) + { + std::auto_ptr<SymbolFile> curr_symfile_ap(create_callback(obj_file)); + + if (curr_symfile_ap.get()) + { + uint32_t sym_file_abilities = curr_symfile_ap->GetAbilities(); + if (sym_file_abilities > best_symfile_abilities) + { + best_symfile_abilities = sym_file_abilities; + best_sym_file_ap = curr_symfile_ap; + } + } + } + } + return best_sym_file_ap.release(); +} + + diff --git a/lldb/source/Symbol/SymbolVendor.mm b/lldb/source/Symbol/SymbolVendor.mm new file mode 100644 index 00000000000..5fb8b0ab8d1 --- /dev/null +++ b/lldb/source/Symbol/SymbolVendor.mm @@ -0,0 +1,386 @@ +//===-- SymbolVendor.mm -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Symbol/SymbolVendor.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolFile.h" + +using namespace lldb; +using namespace lldb_private; + + +//---------------------------------------------------------------------- +// FindPlugin +// +// Platforms can register a callback to use when creating symbol +// vendors to allow for complex debug information file setups, and to +// also allow for finding separate debug information files. +//---------------------------------------------------------------------- +SymbolVendor* +SymbolVendor::FindPlugin (Module* module) +{ + std::auto_ptr<SymbolVendor> instance_ap; + //---------------------------------------------------------------------- + // We currently only have one debug symbol parser... + //---------------------------------------------------------------------- + SymbolVendorCreateInstance create_callback; + for (uint32_t idx = 0; (create_callback = PluginManager::GetSymbolVendorCreateCallbackAtIndex(idx)) != NULL; ++idx) + { + instance_ap.reset(create_callback(module)); + + if (instance_ap.get()) + { + // TODO: make sure this symbol vendor is what we want. We + // currently are just returning the first one we find, but + // we may want to call this function only when we have our + // main executable module and then give all symbol vendor + // plug-ins a chance to compete for who wins. + return instance_ap.release(); + } + } + // The default implementation just tries to create debug information using the + // file representation for the module. + instance_ap.reset(new SymbolVendor(module)); + if (instance_ap.get()) + instance_ap->AddSymbolFileRepresendation(module->GetObjectFile()); + return instance_ap.release(); +} + +//---------------------------------------------------------------------- +// SymbolVendor constructor +//---------------------------------------------------------------------- +SymbolVendor::SymbolVendor(Module *module) : + ModuleChild(module), + m_mutex (Mutex::eMutexTypeRecursive), + m_type_list(), + m_compile_units(), + m_sym_file_ap() +{ + ObjectFile * objfile = module->GetObjectFile(); + ConstString target_triple; + if (objfile && objfile->GetTargetTriple(target_triple)) + { + m_type_list.GetClangASTContext().SetTargetTriple (target_triple.AsCString()); + } +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +SymbolVendor::~SymbolVendor() +{ +} + +//---------------------------------------------------------------------- +// Add a represantion given an object file. +//---------------------------------------------------------------------- +void +SymbolVendor::AddSymbolFileRepresendation(ObjectFile *obj_file) +{ + Mutex::Locker locker(m_mutex); + if (obj_file != NULL) + m_sym_file_ap.reset(SymbolFile::FindPlugin(obj_file)); +} + +bool +SymbolVendor::SetCompileUnitAtIndex +(CompUnitSP& cu, uint32_t idx) +{ + Mutex::Locker locker(m_mutex); + const uint32_t num_compile_units = GetNumCompileUnits(); + if (idx < num_compile_units) + { + // Fire off an assertion if this compile unit already exists for now. + // The partial parsing should take care of only setting the compile + // unit once, so if this assertion fails, we need to make sure that + // we don't have a race condition, or have a second parse of the same + // compile unit. + assert(m_compile_units[idx].get() == NULL); + m_compile_units[idx] = cu; + return true; + } + return false; +} + +uint32_t +SymbolVendor::GetNumCompileUnits() +{ + Mutex::Locker locker(m_mutex); + if (m_compile_units.empty()) + { + if (m_sym_file_ap.get()) + { + // Resize our array of compile unit shared pointers -- which will + // each remain NULL until someone asks for the actual compile unit + // information. When this happens, the symbol file will be asked + // to parse this compile unit information. + m_compile_units.resize(m_sym_file_ap->GetNumCompileUnits()); + } + } + return m_compile_units.size(); +} + +size_t +SymbolVendor::ParseCompileUnitFunctions (const SymbolContext &sc) +{ + Mutex::Locker locker(m_mutex); + if (m_sym_file_ap.get()) + return m_sym_file_ap->ParseCompileUnitFunctions(sc); + return 0; +} + +bool +SymbolVendor::ParseCompileUnitLineTable (const SymbolContext &sc) +{ + Mutex::Locker locker(m_mutex); + if (m_sym_file_ap.get()) + return m_sym_file_ap->ParseCompileUnitLineTable(sc); + return false; +} + +bool +SymbolVendor::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList& support_files) +{ + Mutex::Locker locker(m_mutex); + if (m_sym_file_ap.get()) + return m_sym_file_ap->ParseCompileUnitSupportFiles(sc, support_files); + return false; +} + +size_t +SymbolVendor::ParseFunctionBlocks (const SymbolContext &sc) +{ + Mutex::Locker locker(m_mutex); + if (m_sym_file_ap.get()) + return m_sym_file_ap->ParseFunctionBlocks(sc); + return 0; +} + +size_t +SymbolVendor::ParseTypes (const SymbolContext &sc) +{ + Mutex::Locker locker(m_mutex); + if (m_sym_file_ap.get()) + return m_sym_file_ap->ParseTypes(sc); + return 0; +} + +size_t +SymbolVendor::ParseVariablesForContext (const SymbolContext& sc) +{ + Mutex::Locker locker(m_mutex); + if (m_sym_file_ap.get()) + return m_sym_file_ap->ParseVariablesForContext(sc); + return 0; +} + +Type* +SymbolVendor::ResolveTypeUID(lldb::user_id_t type_uid) +{ + Mutex::Locker locker(m_mutex); + if (m_sym_file_ap.get()) + return m_sym_file_ap->ResolveTypeUID(type_uid); + return NULL; +} + + +uint32_t +SymbolVendor::ResolveSymbolContext (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc) +{ + Mutex::Locker locker(m_mutex); + if (m_sym_file_ap.get()) + return m_sym_file_ap->ResolveSymbolContext(so_addr, resolve_scope, sc); + return 0; +} + +uint32_t +SymbolVendor::ResolveSymbolContext (const FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list) +{ + Mutex::Locker locker(m_mutex); + if (m_sym_file_ap.get()) + return m_sym_file_ap->ResolveSymbolContext(file_spec, line, check_inlines, resolve_scope, sc_list); + return 0; +} + +uint32_t +SymbolVendor::FindGlobalVariables (const ConstString &name, bool append, uint32_t max_matches, VariableList& variables) +{ + Mutex::Locker locker(m_mutex); + if (m_sym_file_ap.get()) + return m_sym_file_ap->FindGlobalVariables(name, append, max_matches, variables); + return 0; +} + +uint32_t +SymbolVendor::FindGlobalVariables (const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variables) +{ + Mutex::Locker locker(m_mutex); + if (m_sym_file_ap.get()) + return m_sym_file_ap->FindGlobalVariables(regex, append, max_matches, variables); + return 0; +} + +uint32_t +SymbolVendor::FindFunctions(const ConstString &name, bool append, SymbolContextList& sc_list) +{ + Mutex::Locker locker(m_mutex); + if (m_sym_file_ap.get()) + return m_sym_file_ap->FindFunctions(name, append, sc_list); + return 0; +} + +uint32_t +SymbolVendor::FindFunctions(const RegularExpression& regex, bool append, SymbolContextList& sc_list) +{ + Mutex::Locker locker(m_mutex); + if (m_sym_file_ap.get()) + return m_sym_file_ap->FindFunctions(regex, append, sc_list); + return 0; +} + + + +//uint32_t +//SymbolVendor::FindTypes(const SymbolContext& sc, const ConstString &name, bool append, uint32_t max_matches, Type::Encoding encoding, const char *udt_name, TypeList& types) +//{ +// Mutex::Locker locker(m_mutex); +// if (m_sym_file_ap.get()) +// { +// lldb::user_id_t udt_uid = LLDB_INVALID_UID; +// if (encoding == Type::user_defined_type) +// udt_uid = UserDefType::GetUserDefTypeUID(udt_name); +// +// return m_sym_file_ap->FindTypes(sc, name, append, max_matches, encoding, udt_uid, types); +// } +// return 0; +//} +// +//uint32_t +//SymbolVendor::FindTypes(const SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, Type::Encoding encoding, const char *udt_name, TypeList& types) +//{ +// Mutex::Locker locker(m_mutex); +// if (m_sym_file_ap.get()) +// { +// lldb::user_id_t udt_uid = LLDB_INVALID_UID; +// +// if (encoding == Type::user_defined_type) +// udt_uid = UserDefType::GetUserDefTypeUID(udt_name); +// +// return m_sym_file_ap->FindTypes(sc, regex, append, max_matches, encoding, udt_uid, types); +// } +// return 0; +//} + +void +SymbolVendor::Dump(Stream *s) +{ + Mutex::Locker locker(m_mutex); + bool show_context = false; + + s->Printf("%.*p: ", (int)sizeof(void*) * 2, this); + s->Indent(); + s->PutCString("SymbolVendor"); + if (m_sym_file_ap.get()) + { + ObjectFile *objfile = m_sym_file_ap->GetObjectFile(); + if (objfile) + { + const FileSpec &objfile_file_spec = objfile->GetFileSpec(); + if (objfile_file_spec) + { + s->PutCString(" ("); + objfile_file_spec.Dump(s); + s->PutChar(')'); + } + } + } + s->EOL(); + s->IndentMore(); + m_type_list.Dump(s, show_context); + + CompileUnitConstIter cu_pos, cu_end; + cu_end = m_compile_units.end(); + for (cu_pos = m_compile_units.begin(); cu_pos != cu_end; ++cu_pos) + { + // We currently only dump the compile units that have been parsed + if (cu_pos->get()) + (*cu_pos)->Dump(s, show_context); + } + + s->IndentLess(); + +} + +CompUnitSP +SymbolVendor::GetCompileUnitAtIndex(uint32_t idx) +{ + Mutex::Locker locker(m_mutex); + CompUnitSP cu_sp; + const uint32_t num_compile_units = GetNumCompileUnits(); + if (idx < num_compile_units) + { + cu_sp = m_compile_units[idx]; + if (cu_sp.get() == NULL) + { + m_compile_units[idx] = m_sym_file_ap->ParseCompileUnitAtIndex(idx); + cu_sp = m_compile_units[idx]; + } + } + return cu_sp; +} + + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ +const char * +SymbolVendor::GetPluginName() +{ + return "SymbolVendor"; +} + +const char * +SymbolVendor::GetShortPluginName() +{ + return "vendor-default"; +} + +uint32_t +SymbolVendor::GetPluginVersion() +{ + return 1; +} + +void +SymbolVendor::GetPluginCommandHelp (const char *command, Stream *strm) +{ +} + +Error +SymbolVendor::ExecutePluginCommand (Args &command, Stream *strm) +{ + Error error; + error.SetErrorString("No plug-in command are currently supported."); + return error; +} + +Log * +SymbolVendor::EnablePluginLogging (Stream *strm, Args &command) +{ + return NULL; +} + + diff --git a/lldb/source/Symbol/Symtab.cpp b/lldb/source/Symbol/Symtab.cpp new file mode 100644 index 00000000000..f1ed356d44b --- /dev/null +++ b/lldb/source/Symbol/Symtab.cpp @@ -0,0 +1,596 @@ +//===-- Symtab.cpp ----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <map> + +#include "lldb/Core/Module.h" +#include "lldb/Core/RegularExpression.h" +#include "lldb/Core/Timer.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/Symtab.h" + +using namespace lldb; +using namespace lldb_private; + + + +Symtab::Symtab(ObjectFile *objfile) : + m_objfile(objfile), + m_symbols(), + m_addr_indexes(), + m_name_to_index() +{ +} + +Symtab::~Symtab() +{ +} + +void +Symtab::Reserve(uint32_t count) +{ + m_symbols.reserve (count); +} + +Symbol * +Symtab::Resize(uint32_t count) +{ + m_symbols.resize (count); + return &m_symbols[0]; +} + +uint32_t +Symtab::AddSymbol(const Symbol& symbol) +{ + uint32_t symbol_idx = m_symbols.size(); + m_name_to_index.Clear(); + m_addr_indexes.clear(); + m_symbols.push_back(symbol); + return symbol_idx; +} + +size_t +Symtab::GetNumSymbols() const +{ + return m_symbols.size(); +} + +void +Symtab::Dump(Stream *s, Process *process) const +{ + const_iterator pos; + s->Printf("%.*p: ", (int)sizeof(void*) * 2, this); + s->Indent(); + const FileSpec &file_spec = m_objfile->GetFileSpec(); + const char * object_name = NULL; + if (m_objfile->GetModule()) + object_name = m_objfile->GetModule()->GetObjectName().GetCString(); + + if (file_spec) + s->Printf("Symtab, file = %s/%s%s%s%s, num_symbols = %u:\n", + file_spec.GetDirectory().AsCString(), + file_spec.GetFilename().AsCString(), + object_name ? "(" : "", + object_name ? object_name : "", + object_name ? ")" : "", + m_symbols.size()); + else + s->Printf("Symtab, num_symbols = %u:\n", m_symbols.size()); + s->IndentMore(); + + if (!m_symbols.empty()) + { + const_iterator begin = m_symbols.begin(); + const_iterator end = m_symbols.end(); + DumpSymbolHeader (s); + for (pos = m_symbols.begin(); pos != end; ++pos) + { + s->Indent(); + pos->Dump(s, process, std::distance(begin, pos)); + } + } + s->IndentLess (); +} + +void +Symtab::Dump(Stream *s, Process *process, std::vector<uint32_t>& indexes) const +{ + const size_t num_symbols = GetNumSymbols(); + s->Printf("%.*p: ", (int)sizeof(void*) * 2, this); + s->Indent(); + s->Printf("Symtab %u symbol indexes (%u symbols total):\n", indexes.size(), m_symbols.size()); + s->IndentMore(); + + if (!indexes.empty()) + { + std::vector<uint32_t>::const_iterator pos; + std::vector<uint32_t>::const_iterator end = indexes.end(); + DumpSymbolHeader (s); + for (pos = indexes.begin(); pos != end; ++pos) + { + uint32_t idx = *pos; + if (idx < num_symbols) + { + s->Indent(); + m_symbols[idx].Dump(s, process, idx); + } + } + } + s->IndentLess (); +} + +void +Symtab::DumpSymbolHeader (Stream *s) +{ + s->Indent(" Debug symbol\n"); + s->Indent(" |Synthetic symbol\n"); + s->Indent(" ||Externally Visible\n"); + s->Indent(" |||\n"); + s->Indent("Index UserID DSX Type File Address/Value Load Address Size Flags Name\n"); + s->Indent("------- ------ --- ------------ ------------------ ------------------ ------------------ ---------- ----------------------------------\n"); +} + +Symbol * +Symtab::SymbolAtIndex(uint32_t idx) +{ + if (idx < m_symbols.size()) + return &m_symbols[idx]; + return NULL; +} + + +const Symbol * +Symtab::SymbolAtIndex(uint32_t idx) const +{ + if (idx < m_symbols.size()) + return &m_symbols[idx]; + return NULL; +} + +//---------------------------------------------------------------------- +// InitNameIndexes +//---------------------------------------------------------------------- +void +Symtab::InitNameIndexes() +{ + Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__); + // Create the name index vector to be able to quickly search by name + const size_t count = m_symbols.size(); + assert(m_objfile != NULL); + assert(m_objfile->GetModule() != NULL); + m_name_to_index.Reserve (count); + + UniqueCStringMap<uint32_t>::Entry entry; + + for (entry.value = 0; entry.value < count; ++entry.value) + { + const Symbol *symbol = &m_symbols[entry.value]; + + // Don't let trampolines get into the lookup by name map + // If we ever need the trampoline symbols to be searchable by name + // we can remove this and then possibly add a new bool to any of the + // Symtab functions that lookup symbols by name to indicate if they + // want trampolines. + if (symbol->IsTrampoline()) + continue; + + const Mangled &mangled = symbol->GetMangled(); + entry.cstring = mangled.GetMangledName().GetCString(); + if (entry.cstring && entry.cstring[0]) + m_name_to_index.Append (entry); + + entry.cstring = mangled.GetDemangledName().GetCString(); + if (entry.cstring && entry.cstring[0]) + m_name_to_index.Append (entry); + } + m_name_to_index.Sort(); +} + +uint32_t +Symtab::AppendSymbolIndexesWithType(SymbolType symbol_type, std::vector<uint32_t>& indexes, uint32_t start_idx, uint32_t end_index) const +{ + uint32_t prev_size = indexes.size(); + + const uint32_t count = std::min<uint32_t> (m_symbols.size(), end_index); + + for (uint32_t i = start_idx; i < count; ++i) + { + if (symbol_type == eSymbolTypeAny || m_symbols[i].GetType() == symbol_type) + indexes.push_back(i); + } + + return indexes.size() - prev_size; +} + +struct SymbolSortInfo +{ + const bool sort_by_load_addr; + const Symbol *symbols; +}; + +int +Symtab::CompareSymbolValueByIndex (void *thunk, const void *a, const void *b) +{ + const Symbol *symbols = (const Symbol *)thunk; + uint32_t index_a = *((uint32_t *) a); + uint32_t index_b = *((uint32_t *) b); + + addr_t value_a; + addr_t value_b; + if (symbols[index_a].GetValue().GetSection() == symbols[index_b].GetValue().GetSection()) + { + value_a = symbols[index_a].GetValue ().GetOffset(); + value_b = symbols[index_b].GetValue ().GetOffset(); + } + else + { + value_a = symbols[index_a].GetValue ().GetFileAddress(); + value_b = symbols[index_b].GetValue ().GetFileAddress(); + } + + if (value_a == value_b) + { + // The if the values are equal, use the original symbol user ID + lldb::user_id_t uid_a = symbols[index_a].GetID(); + lldb::user_id_t uid_b = symbols[index_b].GetID(); + if (uid_a < uid_b) + return -1; + if (uid_a > uid_b) + return 1; + return 0; + } + else if (value_a < value_b) + return -1; + + return 1; +} + +void +Symtab::SortSymbolIndexesByValue (std::vector<uint32_t>& indexes, bool remove_duplicates) const +{ + // No need to sort if we have zero or one items... + if (indexes.size() <= 1) + return; + + // Sort the indexes in place using qsort + ::qsort_r (&indexes[0], indexes.size(), sizeof(uint32_t), (void *)&m_symbols[0], Symtab::CompareSymbolValueByIndex); + + // Remove any duplicates if requested + if (remove_duplicates) + std::unique(indexes.begin(), indexes.end()); +} + +uint32_t +Symtab::AppendSymbolIndexesWithName(const ConstString& symbol_name, std::vector<uint32_t>& indexes) +{ + Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__); + if (symbol_name) + { + const size_t old_size = indexes.size(); + if (m_name_to_index.IsEmpty()) + InitNameIndexes(); + + const char *symbol_cstr = symbol_name.GetCString(); + const UniqueCStringMap<uint32_t>::Entry *entry_ptr; + for (entry_ptr = m_name_to_index.FindFirstValueForName (symbol_cstr); + entry_ptr!= NULL; + entry_ptr = m_name_to_index.FindNextValueForName (symbol_cstr, entry_ptr)) + { + indexes.push_back (entry_ptr->value); + } + return indexes.size() - old_size; + } + return 0; +} + +uint32_t +Symtab::AppendSymbolIndexesWithNameAndType(const ConstString& symbol_name, SymbolType symbol_type, std::vector<uint32_t>& indexes) +{ + if (AppendSymbolIndexesWithName(symbol_name, indexes) > 0) + { + std::vector<uint32_t>::iterator pos = indexes.begin(); + while (pos != indexes.end()) + { + if (symbol_type == eSymbolTypeAny || m_symbols[*pos].GetType() == symbol_type) + ++pos; + else + indexes.erase(pos); + } + } + return indexes.size(); +} + +uint32_t +Symtab::AppendSymbolIndexesMatchingRegExAndType (const RegularExpression ®exp, SymbolType symbol_type, std::vector<uint32_t>& indexes) +{ + uint32_t prev_size = indexes.size(); + uint32_t sym_end = m_symbols.size(); + + for (int i = 0; i < sym_end; i++) + { + if (symbol_type == eSymbolTypeAny || m_symbols[i].GetType() == symbol_type) + { + const char *name = m_symbols[i].GetMangled().GetName().AsCString(); + if (name) + { + if (regexp.Execute (name)) + indexes.push_back(i); + } + } + } + return indexes.size() - prev_size; + +} + +Symbol * +Symtab::FindSymbolWithType(SymbolType symbol_type, uint32_t& start_idx) +{ + const size_t count = m_symbols.size(); + for (uint32_t idx = start_idx; idx < count; ++idx) + { + if (symbol_type == eSymbolTypeAny || m_symbols[idx].GetType() == symbol_type) + { + start_idx = idx; + return &m_symbols[idx]; + } + } + return NULL; +} + +const Symbol * +Symtab::FindSymbolWithType(SymbolType symbol_type, uint32_t& start_idx) const +{ + const size_t count = m_symbols.size(); + for (uint32_t idx = start_idx; idx < count; ++idx) + { + if (symbol_type == eSymbolTypeAny || m_symbols[idx].GetType() == symbol_type) + { + start_idx = idx; + return &m_symbols[idx]; + } + } + return NULL; +} + +size_t +Symtab::FindAllSymbolsWithNameAndType (const ConstString &name, SymbolType symbol_type, std::vector<uint32_t>& symbol_indexes) +{ + Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__); + // Initialize all of the lookup by name indexes before converting NAME + // to a uniqued string NAME_STR below. + if (m_name_to_index.IsEmpty()) + InitNameIndexes(); + + if (name) + { + // The string table did have a string that matched, but we need + // to check the symbols and match the symbol_type if any was given. + AppendSymbolIndexesWithNameAndType(name, symbol_type, symbol_indexes); + } + return symbol_indexes.size(); +} + +size_t +Symtab::FindAllSymbolsMatchingRexExAndType (const RegularExpression ®ex, SymbolType symbol_type, std::vector<uint32_t>& symbol_indexes) +{ + AppendSymbolIndexesMatchingRegExAndType(regex, symbol_type, symbol_indexes); + return symbol_indexes.size(); +} + +Symbol * +Symtab::FindFirstSymbolWithNameAndType (const ConstString &name, SymbolType symbol_type) +{ + Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__); + if (m_name_to_index.IsEmpty()) + InitNameIndexes(); + + if (name) + { + std::vector<uint32_t> matching_indexes; + // The string table did have a string that matched, but we need + // to check the symbols and match the symbol_type if any was given. + if (AppendSymbolIndexesWithNameAndType(name, symbol_type, matching_indexes)) + { + std::vector<uint32_t>::const_iterator pos, end = matching_indexes.end(); + for (pos = matching_indexes.begin(); pos != end; ++pos) + { + Symbol *symbol = SymbolAtIndex(*pos); + + if (symbol->Compare(name, symbol_type)) + return symbol; + } + } + } + return NULL; +} + +typedef struct +{ + const Symtab *symtab; + const addr_t file_addr; + Symbol *match_symbol; + const uint32_t *match_index_ptr; + addr_t match_offset; +} SymbolSearchInfo; + +static int +SymbolWithFileAddress (SymbolSearchInfo *info, const uint32_t *index_ptr) +{ + const Symbol *curr_symbol = info->symtab->SymbolAtIndex (index_ptr[0]); + if (curr_symbol == NULL) + return -1; + + const addr_t info_file_addr = info->file_addr; + + // lldb::Symbol::GetAddressRangePtr() will only return a non NULL address + // range if the symbol has a section! + const AddressRange *curr_range = curr_symbol->GetAddressRangePtr(); + if (curr_range) + { + const addr_t curr_file_addr = curr_range->GetBaseAddress().GetFileAddress(); + if (info_file_addr < curr_file_addr) + return -1; + if (info_file_addr > curr_file_addr) + return +1; + info->match_symbol = const_cast<Symbol *>(curr_symbol); + info->match_index_ptr = index_ptr; + return 0; + } + + return -1; +} + +static int +SymbolWithClosestFileAddress (SymbolSearchInfo *info, const uint32_t *index_ptr) +{ + const Symbol *symbol = info->symtab->SymbolAtIndex (index_ptr[0]); + if (symbol == NULL) + return -1; + + const addr_t info_file_addr = info->file_addr; + const AddressRange *curr_range = symbol->GetAddressRangePtr(); + if (curr_range) + { + const addr_t curr_file_addr = curr_range->GetBaseAddress().GetFileAddress(); + if (info_file_addr < curr_file_addr) + return -1; + + // Since we are finding the closest symbol that is greater than or equal + // to 'info->file_addr' we set the symbol here. This will get set + // multiple times, but after the search is done it will contain the best + // symbol match + info->match_symbol = const_cast<Symbol *>(symbol); + info->match_index_ptr = index_ptr; + info->match_offset = info_file_addr - curr_file_addr; + + if (info_file_addr > curr_file_addr) + return +1; + return 0; + } + return -1; +} + +static SymbolSearchInfo +FindIndexPtrForSymbolContainingAddress(Symtab* symtab, addr_t file_addr, const uint32_t* indexes, uint32_t num_indexes) +{ + SymbolSearchInfo info = { symtab, file_addr, NULL, NULL, 0 }; + bsearch(&info, indexes, num_indexes, sizeof(uint32_t), (comparison_function)SymbolWithClosestFileAddress); + return info; +} + + +void +Symtab::InitAddressIndexes() +{ + if (m_addr_indexes.empty()) + { + AppendSymbolIndexesWithType (eSymbolTypeFunction, m_addr_indexes); + AppendSymbolIndexesWithType (eSymbolTypeGlobal, m_addr_indexes); + AppendSymbolIndexesWithType (eSymbolTypeStatic, m_addr_indexes); + AppendSymbolIndexesWithType (eSymbolTypeCode, m_addr_indexes); + AppendSymbolIndexesWithType (eSymbolTypeTrampoline, m_addr_indexes); + AppendSymbolIndexesWithType (eSymbolTypeData, m_addr_indexes); + SortSymbolIndexesByValue(m_addr_indexes, true); + m_addr_indexes.push_back(UINT32_MAX); // Terminator for bsearch since we might need to look at the next symbol + } +} + +size_t +Symtab::CalculateSymbolSize (Symbol *symbol) +{ + // Make sure this symbol is from this symbol table... + if (symbol < m_symbols.data() && symbol >= m_symbols.data() + m_symbols.size()) + return 0; + + // See if this symbol already has a byte size? + size_t byte_size = symbol->GetByteSize(); + + if (byte_size) + { + // It does, just return it + return byte_size; + } + + // Else if this is an address based symbol, figure out the delta between + // it and the next address based symbol + if (symbol->GetAddressRangePtr()) + { + if (m_addr_indexes.empty()) + InitAddressIndexes(); + const size_t num_addr_indexes = m_addr_indexes.size(); + SymbolSearchInfo info = FindIndexPtrForSymbolContainingAddress(this, symbol->GetAddressRangePtr()->GetBaseAddress().GetFileAddress(), m_addr_indexes.data(), num_addr_indexes); + if (info.match_index_ptr != NULL) + { + const lldb::addr_t curr_file_addr = symbol->GetAddressRangePtr()->GetBaseAddress().GetFileAddress(); + // We can figure out the address range of all symbols except the + // last one by taking the delta between the current symbol and + // the next symbol + + for (uint32_t addr_index = info.match_index_ptr - m_addr_indexes.data() + 1; + addr_index < num_addr_indexes; + ++addr_index) + { + Symbol *next_symbol = SymbolAtIndex(m_addr_indexes[addr_index]); + if (next_symbol == NULL) + break; + + assert (next_symbol->GetAddressRangePtr()); + const lldb::addr_t next_file_addr = next_symbol->GetAddressRangePtr()->GetBaseAddress().GetFileAddress(); + if (next_file_addr > curr_file_addr) + { + byte_size = next_file_addr - curr_file_addr; + symbol->GetAddressRangePtr()->SetByteSize(byte_size); + symbol->SetSizeIsSynthesized(true); + break; + } + } + } + } + return byte_size; +} + +Symbol * +Symtab::FindSymbolWithFileAddress (addr_t file_addr) +{ + if (m_addr_indexes.empty()) + InitAddressIndexes(); + + SymbolSearchInfo info = { this, file_addr, NULL, NULL, 0 }; + + uint32_t* match = (uint32_t*)bsearch(&info, &m_addr_indexes[0], m_addr_indexes.size(), sizeof(uint32_t), (comparison_function)SymbolWithFileAddress); + if (match) + return SymbolAtIndex (*match); + return NULL; +} + + +Symbol * +Symtab::FindSymbolContainingFileAddress (addr_t file_addr, const uint32_t* indexes, uint32_t num_indexes) +{ + SymbolSearchInfo info = { this, file_addr, NULL, NULL, 0 }; + + bsearch(&info, indexes, num_indexes, sizeof(uint32_t), (comparison_function)SymbolWithClosestFileAddress); + + if (info.match_symbol) + { + if (info.match_offset < CalculateSymbolSize(info.match_symbol)) + return info.match_symbol; + } + return NULL; +} + +Symbol * +Symtab::FindSymbolContainingFileAddress (addr_t file_addr) +{ + if (m_addr_indexes.empty()) + InitAddressIndexes(); + + return FindSymbolContainingFileAddress (file_addr, &m_addr_indexes[0], m_addr_indexes.size()); +} + diff --git a/lldb/source/Symbol/Type.cpp b/lldb/source/Symbol/Type.cpp new file mode 100644 index 00000000000..9338ea2839a --- /dev/null +++ b/lldb/source/Symbol/Type.cpp @@ -0,0 +1,1531 @@ +//===-- Type.cpp ------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Other libraries and framework includes +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclGroup.h" +#include "clang/AST/RecordLayout.h" + +#include "clang/Basic/Builtins.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" + +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/raw_ostream.h" + +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/Scalar.h" +#include "lldb/Core/StreamString.h" + +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolContextScope.h" +#include "lldb/Symbol/SymbolFile.h" +#include "lldb/Symbol/Type.h" +#include "lldb/Symbol/TypeList.h" + +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" + +lldb_private::Type::Type +( + lldb::user_id_t uid, + SymbolFile* symbol_file, + const ConstString &name, + uint64_t byte_size, + SymbolContextScope *context, + lldb::user_id_t encoding_uid, + EncodingUIDType encoding_uid_type, + const Declaration& decl, + void *clang_type +) : + UserID (uid), + m_name (name), + m_byte_size (byte_size), + m_symbol_file (symbol_file), + m_context (context), + m_encoding_uid (encoding_uid), + m_encoding_uid_type (encoding_uid_type), + m_decl (decl), + m_clang_qual_type (clang_type) +{ +} + +lldb_private::Type::Type () : + UserID (0), + m_name ("<INVALID TYPE>"), + m_byte_size (0), + m_symbol_file (NULL), + m_context (), + m_encoding_uid (0), + m_encoding_uid_type (eTypeInvalid), + m_decl (), + m_clang_qual_type (NULL) +{ +} + + +const lldb_private::Type& +lldb_private::Type::operator= (const Type& rhs) +{ + if (this != &rhs) + { + UserID::operator= (rhs); + m_name = rhs.m_name; + m_byte_size = rhs.m_byte_size; + m_symbol_file = rhs.m_symbol_file; + m_context = rhs.m_context; + m_encoding_uid = rhs.m_encoding_uid; + m_decl = rhs.m_decl; + m_clang_qual_type = rhs.m_clang_qual_type; + } + return *this; +} + + +void +lldb_private::Type::Dump (Stream *s, bool show_context) +{ + s->Printf("%.*p: ", (int)sizeof(void*) * 2, this); + s->Indent(); + *s << "Type" << (const UserID&)*this << ' '; + if (m_name) + *s << ", name = \"" << m_name << "\""; + + if (m_byte_size != 0) + s->Printf(", size = %zu", m_byte_size); + + if (show_context && m_context != NULL) + { + s->PutCString(", context = ( "); + m_context->DumpSymbolContext(s); + s->PutCString(" )"); + } + + m_decl.Dump(s); + + clang::QualType qual_type(clang::QualType::getFromOpaquePtr(m_clang_qual_type)); + + if (qual_type.getTypePtr()) + { + *s << ", clang_type = "; + + clang::TagType *tag_type = dyn_cast<clang::TagType>(qual_type.getTypePtr()); + clang::TagDecl *tag_decl = NULL; + if (tag_type) + tag_decl = tag_type->getDecl(); + + if (tag_decl) + { + s->EOL(); + s->EOL(); + tag_decl->print(llvm::fouts(), 0); + s->EOL(); + } + else + { + const clang::TypedefType *typedef_type = qual_type->getAs<clang::TypedefType>(); + if (typedef_type) + { + const clang::TypedefDecl *typedef_decl = typedef_type->getDecl(); + std::string clang_typedef_name (typedef_decl->getQualifiedNameAsString()); + if (!clang_typedef_name.empty()) + *s << " (" << clang_typedef_name.c_str() << ')'; + } + else + { + // We have a clang type, lets show it + TypeList *type_list = GetTypeList(); + if (type_list) + { + clang::ASTContext *ast_context = GetClangAST(); + if (ast_context) + { + std::string clang_type_name(qual_type.getAsString()); + if (!clang_type_name.empty()) + *s << " (" << clang_type_name.c_str() << ')'; + } + } + } + } + } + else if (m_encoding_uid != LLDB_INVALID_UID) + { + *s << ", type_uid = " << m_encoding_uid; + switch (m_encoding_uid_type) + { + case eIsTypeWithUID: s->PutCString(" (unresolved type)"); break; + case eIsConstTypeWithUID: s->PutCString(" (unresolved const type)"); break; + case eIsRestrictTypeWithUID: s->PutCString(" (unresolved restrict type)"); break; + case eIsVolatileTypeWithUID: s->PutCString(" (unresolved volatile type)"); break; + case eTypedefToTypeWithUID: s->PutCString(" (unresolved typedef)"); break; + case ePointerToTypeWithUID: s->PutCString(" (unresolved pointer)"); break; + case eLValueReferenceToTypeWithUID: s->PutCString(" (unresolved L value reference)"); break; + case eRValueReferenceToTypeWithUID: s->PutCString(" (unresolved R value reference)"); break; + } + } + +// +// if (m_access) +// s->Printf(", access = %u", m_access); + s->EOL(); +} + +const lldb_private::ConstString & +lldb_private::Type::GetName() +{ + if (!(m_name)) + { + if (ResolveClangType()) + { + std::string type_name = ClangASTContext::GetTypeName (m_clang_qual_type); + if (!type_name.empty()) + m_name.SetCString (type_name.c_str()); + } + } + return m_name; +} + +int +lldb_private::Type::DumpClangTypeName(Stream *s, void *clang_type) +{ + clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type)); + std::string type_name; + const clang::TypedefType *typedef_type = qual_type->getAs<clang::TypedefType>(); + if (typedef_type) + { + const clang::TypedefDecl *typedef_decl = typedef_type->getDecl(); + type_name = typedef_decl->getQualifiedNameAsString(); + } + else + { + type_name = qual_type.getAsString(); + } + if (!type_name.empty()) + return s->Printf("(%s) ", type_name.c_str()); + return 0; +} + +lldb_private::ConstString +lldb_private::Type::GetClangTypeName (void *clang_type) +{ + ConstString clang_type_name; + if (clang_type) + { + clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type)); + + const clang::TypedefType *typedef_type = qual_type->getAs<clang::TypedefType>(); + if (typedef_type) + { + const clang::TypedefDecl *typedef_decl = typedef_type->getDecl(); + std::string clang_typedef_name (typedef_decl->getQualifiedNameAsString()); + if (!clang_typedef_name.empty()) + clang_type_name.SetCString (clang_typedef_name.c_str()); + } + else + { + std::string type_name(qual_type.getAsString()); + if (!type_name.empty()) + clang_type_name.SetCString (type_name.c_str()); + } + } + else + { + clang_type_name.SetCString ("<invalid>"); + } + + return clang_type_name; +} + + + +void +lldb_private::Type::DumpTypeName(Stream *s) +{ + GetName().Dump(s, "<invalid-type-name>"); +} + + +void +lldb_private::Type::DumpValue +( + lldb_private::ExecutionContext *exe_ctx, + lldb_private::Stream *s, + const lldb_private::DataExtractor &data, + uint32_t data_byte_offset, + bool show_types, + bool show_summary, + bool verbose, + lldb::Format format +) +{ + if (ResolveClangType()) + { + if (show_types) + { + s->PutChar('('); + if (verbose) + s->Printf("Type{0x%8.8x} ", GetID()); + DumpTypeName (s); + s->PutCString(") "); + } + + lldb_private::Type::DumpValue (exe_ctx, + GetClangAST (), + m_clang_qual_type, + s, + format == lldb::eFormatDefault ? GetFormat() : format, + data, + data_byte_offset, + GetByteSize(), + 0, // Bitfield bit size + 0, // Bitfield bit offset + show_types, + show_summary, + verbose, + 0); + } +} + + +void +lldb_private::Type::DumpSummary +( + ExecutionContext *exe_ctx, + clang::ASTContext *ast_context, + void *clang_type, + Stream *s, + const lldb_private::DataExtractor &data, + uint32_t data_byte_offset, + size_t data_byte_size +) +{ + uint32_t length = 0; + clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type)); + if (ClangASTContext::IsCStringType (clang_type, length)) + { + + if (exe_ctx && exe_ctx->process) + { + uint32_t offset = data_byte_offset; + lldb::addr_t pointer_addresss = data.GetMaxU64(&offset, data_byte_size); + const size_t k_max_buf_size = length ? length : 256; + uint8_t buf[k_max_buf_size + 1]; + lldb_private::DataExtractor data(buf, k_max_buf_size, exe_ctx->process->GetByteOrder(), 4); + buf[k_max_buf_size] = '\0'; + size_t bytes_read; + size_t total_cstr_len = 0; + Error error; + while ((bytes_read = exe_ctx->process->ReadMemory (pointer_addresss, buf, k_max_buf_size, error)) > 0) + { + const size_t len = strlen((const char *)buf); + if (len == 0) + break; + if (total_cstr_len == 0) + s->PutCString (" \""); + data.Dump(s, 0, lldb::eFormatChar, 1, len, UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0); + total_cstr_len += len; + if (len < k_max_buf_size) + break; + pointer_addresss += total_cstr_len; + } + if (total_cstr_len > 0) + s->PutChar ('"'); + } + } +} + +#define DEPTH_INCREMENT 2 +void +lldb_private::Type::DumpValue +( + ExecutionContext *exe_ctx, + clang::ASTContext *ast_context, + void *clang_type, + Stream *s, + lldb::Format format, + const lldb_private::DataExtractor &data, + uint32_t data_byte_offset, + size_t data_byte_size, + uint32_t bitfield_bit_size, + uint32_t bitfield_bit_offset, + bool show_types, + bool show_summary, + bool verbose, + uint32_t depth +) +{ + clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type)); + switch (qual_type->getTypeClass()) + { + case clang::Type::Record: + { + const clang::RecordType *record_type = cast<clang::RecordType>(qual_type.getTypePtr()); + const clang::RecordDecl *record_decl = record_type->getDecl(); + assert(record_decl); + uint32_t field_bit_offset = 0; + uint32_t field_byte_offset = 0; + const clang::ASTRecordLayout &record_layout = ast_context->getASTRecordLayout(record_decl); + uint32_t child_idx = 0; + + + const clang::CXXRecordDecl *cxx_record_decl = dyn_cast<clang::CXXRecordDecl>(record_decl); + if (cxx_record_decl) + { + // We might have base classes to print out first + clang::CXXRecordDecl::base_class_const_iterator base_class, base_class_end; + for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end(); + base_class != base_class_end; + ++base_class) + { + const clang::CXXRecordDecl *base_class_decl = cast<clang::CXXRecordDecl>(base_class->getType()->getAs<clang::RecordType>()->getDecl()); + + // Skip empty base classes + if (verbose == false && ClangASTContext::RecordHasFields(base_class_decl) == false) + continue; + + if (base_class->isVirtual()) + field_bit_offset = record_layout.getVBaseClassOffset(base_class_decl); + else + field_bit_offset = record_layout.getBaseClassOffset(base_class_decl); + field_byte_offset = field_bit_offset / 8; + assert (field_bit_offset % 8 == 0); + if (child_idx == 0) + s->PutChar('{'); + else + s->PutChar(','); + + clang::QualType base_class_qual_type = base_class->getType(); + std::string base_class_type_name(base_class_qual_type.getAsString()); + + // Indent and print the base class type name + s->Printf("\n%*s%s ", depth + DEPTH_INCREMENT, "", base_class_type_name.c_str()); + + std::pair<uint64_t, unsigned> base_class_type_info = ast_context->getTypeInfo(base_class_qual_type); + + // Dump the value of the member + Type::DumpValue ( + exe_ctx, + ast_context, // The clang AST context for this type + base_class_qual_type.getAsOpaquePtr(),// The clang type we want to dump + s, // Stream to dump to + Type::GetFormat(base_class_qual_type.getAsOpaquePtr()), // The format with which to display the member + data, // Data buffer containing all bytes for this type + data_byte_offset + field_byte_offset,// Offset into "data" where to grab value from + base_class_type_info.first / 8, // Size of this type in bytes + 0, // Bitfield bit size + 0, // Bitfield bit offset + show_types, // Boolean indicating if we should show the variable types + show_summary, // Boolean indicating if we should show a summary for the current type + verbose, // Verbose output? + depth + DEPTH_INCREMENT); // Scope depth for any types that have children + + ++child_idx; + } + } + const unsigned num_fields = record_layout.getFieldCount(); + + uint32_t field_idx = 0; + clang::RecordDecl::field_iterator field, field_end; + for (field = record_decl->field_begin(), field_end = record_decl->field_end(); field != field_end; ++field, ++field_idx, ++child_idx) + { + // Print the starting squiggly bracket (if this is the + // first member) or comman (for member 2 and beyong) for + // the struct/union/class member. + if (child_idx == 0) + s->PutChar('{'); + else + s->PutChar(','); + + // Indent + s->Printf("\n%*s", depth + DEPTH_INCREMENT, ""); + + clang::QualType field_type = field->getType(); + // Print the member type if requested + // Figure out the type byte size (field_type_info.first) and + // alignment (field_type_info.second) from the AST context. + std::pair<uint64_t, unsigned> field_type_info = ast_context->getTypeInfo(field_type); + assert(field_idx < num_fields); + // Figure out the field offset within the current struct/union/class type + field_bit_offset = record_layout.getFieldOffset (field_idx); + field_byte_offset = field_bit_offset / 8; + uint32_t field_bitfield_bit_size = 0; + uint32_t field_bitfield_bit_offset = 0; + if (ClangASTContext::FieldIsBitfield (ast_context, *field, field_bitfield_bit_size)) + field_bitfield_bit_offset = field_bit_offset % 8; + + if (show_types) + { + std::string field_type_name(field_type.getAsString()); + if (field_bitfield_bit_size > 0) + s->Printf("(%s:%u) ", field_type_name.c_str(), field_bitfield_bit_size); + else + s->Printf("(%s) ", field_type_name.c_str()); + } + // Print the member name and equal sign + s->Printf("%s = ", field->getNameAsString().c_str()); + + + // Dump the value of the member + Type::DumpValue ( + exe_ctx, + ast_context, // The clang AST context for this type + field_type.getAsOpaquePtr(), // The clang type we want to dump + s, // Stream to dump to + Type::GetFormat(field_type.getAsOpaquePtr()), // The format with which to display the member + data, // Data buffer containing all bytes for this type + data_byte_offset + field_byte_offset,// Offset into "data" where to grab value from + field_type_info.first / 8, // Size of this type in bytes + field_bitfield_bit_size, // Bitfield bit size + field_bitfield_bit_offset, // Bitfield bit offset + show_types, // Boolean indicating if we should show the variable types + show_summary, // Boolean indicating if we should show a summary for the current type + verbose, // Verbose output? + depth + DEPTH_INCREMENT); // Scope depth for any types that have children + } + + // Indent the trailing squiggly bracket + if (child_idx > 0) + s->Printf("\n%*s}", depth, ""); + } + return; + + case clang::Type::Enum: + { + const clang::EnumType *enum_type = cast<clang::EnumType>(qual_type.getTypePtr()); + const clang::EnumDecl *enum_decl = enum_type->getDecl(); + assert(enum_decl); + clang::EnumDecl::enumerator_iterator enum_pos, enum_end_pos; + uint32_t offset = data_byte_offset; + const int64_t enum_value = data.GetMaxU64Bitfield(&offset, data_byte_size, bitfield_bit_size, bitfield_bit_offset); + for (enum_pos = enum_decl->enumerator_begin(), enum_end_pos = enum_decl->enumerator_end(); enum_pos != enum_end_pos; ++enum_pos) + { + if (enum_pos->getInitVal() == enum_value) + { + s->Printf("%s", enum_pos->getNameAsCString()); + return; + } + } + // If we have gotten here we didn't get find the enumerator in the + // enum decl, so just print the integer. + s->Printf("%lli", enum_value); + } + return; + + case clang::Type::ConstantArray: + { + const clang::ConstantArrayType *array = cast<clang::ConstantArrayType>(qual_type.getTypePtr()); + bool is_array_of_characters = false; + clang::QualType element_qual_type = array->getElementType(); + + clang::Type *canonical_type = element_qual_type->getCanonicalTypeInternal().getTypePtr(); + if (canonical_type) + is_array_of_characters = canonical_type->isCharType(); + + const uint64_t element_count = array->getSize().getLimitedValue(); + + std::pair<uint64_t, unsigned> field_type_info = ast_context->getTypeInfo(element_qual_type); + + uint32_t element_idx = 0; + uint32_t element_offset = 0; + uint64_t element_byte_size = field_type_info.first / 8; + uint32_t element_stride = element_byte_size; + + if (is_array_of_characters) + { + s->PutChar('"'); + data.Dump(s, data_byte_offset, lldb::eFormatChar, element_byte_size, element_count, UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0); + s->PutChar('"'); + return; + } + else + { + lldb::Format element_format = Type::GetFormat(element_qual_type.getAsOpaquePtr()); + + for (element_idx = 0; element_idx < element_count; ++element_idx) + { + // Print the starting squiggly bracket (if this is the + // first member) or comman (for member 2 and beyong) for + // the struct/union/class member. + if (element_idx == 0) + s->PutChar('{'); + else + s->PutChar(','); + + // Indent and print the index + s->Printf("\n%*s[%u] ", depth + DEPTH_INCREMENT, "", element_idx); + + // Figure out the field offset within the current struct/union/class type + element_offset = element_idx * element_stride; + + // Dump the value of the member + Type::DumpValue ( + exe_ctx, + ast_context, // The clang AST context for this type + element_qual_type.getAsOpaquePtr(), // The clang type we want to dump + s, // Stream to dump to + element_format, // The format with which to display the element + data, // Data buffer containing all bytes for this type + data_byte_offset + element_offset,// Offset into "data" where to grab value from + element_byte_size, // Size of this type in bytes + 0, // Bitfield bit size + 0, // Bitfield bit offset + show_types, // Boolean indicating if we should show the variable types + show_summary, // Boolean indicating if we should show a summary for the current type + verbose, // Verbose output? + depth + DEPTH_INCREMENT); // Scope depth for any types that have children + } + + // Indent the trailing squiggly bracket + if (element_idx > 0) + s->Printf("\n%*s}", depth, ""); + } + } + return; + + case clang::Type::Typedef: + { + clang::QualType typedef_qual_type = cast<clang::TypedefType>(qual_type)->LookThroughTypedefs(); + lldb::Format typedef_format = lldb_private::Type::GetFormat(typedef_qual_type.getAsOpaquePtr()); + std::pair<uint64_t, unsigned> typedef_type_info = ast_context->getTypeInfo(typedef_qual_type); + uint64_t typedef_byte_size = typedef_type_info.first / 8; + + return Type::DumpValue( + exe_ctx, + ast_context, // The clang AST context for this type + typedef_qual_type.getAsOpaquePtr(), // The clang type we want to dump + s, // Stream to dump to + typedef_format, // The format with which to display the element + data, // Data buffer containing all bytes for this type + data_byte_offset, // Offset into "data" where to grab value from + typedef_byte_size, // Size of this type in bytes + bitfield_bit_size, // Bitfield bit size + bitfield_bit_offset,// Bitfield bit offset + show_types, // Boolean indicating if we should show the variable types + show_summary, // Boolean indicating if we should show a summary for the current type + verbose, // Verbose output? + depth); // Scope depth for any types that have children + } + break; + + default: + // We are down the a scalar type that we just need to display. + data.Dump(s, data_byte_offset, format, data_byte_size, 1, UINT32_MAX, LLDB_INVALID_ADDRESS, bitfield_bit_size, bitfield_bit_offset); + + if (show_summary) + Type::DumpSummary (exe_ctx, ast_context, clang_type, s, data, data_byte_offset, data_byte_size); + break; + } +} + +bool +lldb_private::Type::DumpTypeValue +( + Stream *s, + clang::ASTContext *ast_context, + void *clang_type, + lldb::Format format, + const lldb_private::DataExtractor &data, + uint32_t byte_offset, + size_t byte_size, + uint32_t bitfield_bit_size, + uint32_t bitfield_bit_offset +) +{ + clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type)); + if (ClangASTContext::IsAggregateType (clang_type)) + { + return 0; + } + else + { + switch (qual_type->getTypeClass()) + { + case clang::Type::Enum: + { + const clang::EnumType *enum_type = cast<clang::EnumType>(qual_type.getTypePtr()); + const clang::EnumDecl *enum_decl = enum_type->getDecl(); + assert(enum_decl); + clang::EnumDecl::enumerator_iterator enum_pos, enum_end_pos; + uint32_t offset = byte_offset; + const int64_t enum_value = data.GetMaxU64Bitfield (&offset, byte_size, bitfield_bit_size, bitfield_bit_offset); + for (enum_pos = enum_decl->enumerator_begin(), enum_end_pos = enum_decl->enumerator_end(); enum_pos != enum_end_pos; ++enum_pos) + { + if (enum_pos->getInitVal() == enum_value) + { + s->PutCString (enum_pos->getNameAsCString()); + return true; + } + } + // If we have gotten here we didn't get find the enumerator in the + // enum decl, so just print the integer. + + s->Printf("%lli", enum_value); + return true; + } + break; + + case clang::Type::Typedef: + { + clang::QualType typedef_qual_type = cast<clang::TypedefType>(qual_type)->LookThroughTypedefs(); + lldb::Format typedef_format = Type::GetFormat(typedef_qual_type.getAsOpaquePtr()); + std::pair<uint64_t, unsigned> typedef_type_info = ast_context->getTypeInfo(typedef_qual_type); + uint64_t typedef_byte_size = typedef_type_info.first / 8; + + return Type::DumpTypeValue( + s, + ast_context, // The clang AST context for this type + typedef_qual_type.getAsOpaquePtr(), // The clang type we want to dump + typedef_format, // The format with which to display the element + data, // Data buffer containing all bytes for this type + byte_offset, // Offset into "data" where to grab value from + typedef_byte_size, // Size of this type in bytes + bitfield_bit_size, // Size in bits of a bitfield value, if zero don't treat as a bitfield + bitfield_bit_offset); // Offset in bits of a bitfield value if bitfield_bit_size != 0 + } + break; + + default: + // We are down the a scalar type that we just need to display. + return data.Dump(s, + byte_offset, + format, + byte_size, + 1, + UINT32_MAX, + LLDB_INVALID_ADDRESS, + bitfield_bit_size, + bitfield_bit_offset); + break; + } + } + return 0; +} + +bool +lldb_private::Type::GetValueAsScalar +( + clang::ASTContext *ast_context, + void *clang_type, + const lldb_private::DataExtractor &data, + uint32_t data_byte_offset, + size_t data_byte_size, + Scalar &value +) +{ + clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type)); + + if (ClangASTContext::IsAggregateType (clang_type)) + { + return false; // Aggregate types don't have scalar values + } + else + { + uint32_t count = 0; + lldb::Encoding encoding = Type::GetEncoding (clang_type, count); + + if (encoding == lldb::eEncodingInvalid || count != 1) + return false; + + uint64_t bit_width = ast_context->getTypeSize(qual_type); + uint32_t byte_size = (bit_width + 7 ) / 8; + uint32_t offset = data_byte_offset; + switch (encoding) + { + case lldb::eEncodingUint: + if (byte_size <= sizeof(unsigned long long)) + { + uint64_t uval64 = data.GetMaxU64 (&offset, byte_size); + if (byte_size <= sizeof(unsigned int)) + { + value = (unsigned int)uval64; + return true; + } + else if (byte_size <= sizeof(unsigned long)) + { + value = (unsigned long)uval64; + return true; + } + else if (byte_size <= sizeof(unsigned long long)) + { + value = (unsigned long long )uval64; + return true; + } + else + value.Clear(); + } + break; + + case lldb::eEncodingSint: + if (byte_size <= sizeof(long long)) + { + int64_t sval64 = (int64_t)data.GetMaxU64 (&offset, byte_size); + if (byte_size <= sizeof(int)) + { + value = (int)sval64; + return true; + } + else if (byte_size <= sizeof(long)) + { + value = (long)sval64; + return true; + } + else if (byte_size <= sizeof(long long)) + { + value = (long long )sval64; + return true; + } + else + value.Clear(); + } + break; + + case lldb::eEncodingIEEE754: + if (byte_size <= sizeof(long double)) + { + uint32_t u32; + uint64_t u64; + if (byte_size == sizeof(float)) + { + if (sizeof(float) == sizeof(uint32_t)) + { + u32 = data.GetU32(&offset); + value = *((float *)&u32); + return true; + } + else if (sizeof(float) == sizeof(uint64_t)) + { + u64 = data.GetU64(&offset); + value = *((float *)&u64); + return true; + } + } + else + if (byte_size == sizeof(double)) + { + if (sizeof(double) == sizeof(uint32_t)) + { + u32 = data.GetU32(&offset); + value = *((double *)&u32); + return true; + } + else if (sizeof(double) == sizeof(uint64_t)) + { + u64 = data.GetU64(&offset); + value = *((double *)&u64); + return true; + } + } + else + if (byte_size == sizeof(long double)) + { + if (sizeof(long double) == sizeof(uint32_t)) + { + u32 = data.GetU32(&offset); + value = *((long double *)&u32); + return true; + } + else if (sizeof(long double) == sizeof(uint64_t)) + { + u64 = data.GetU64(&offset); + value = *((long double *)&u64); + return true; + } + } + } + break; + } + } + return false; +} + +bool +lldb_private::Type::SetValueFromScalar +( + clang::ASTContext *ast_context, + void *clang_type, + const Scalar &value, + Stream &strm +) +{ + clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type)); + + // Aggregate types don't have scalar values + if (!ClangASTContext::IsAggregateType (clang_type)) + { + strm.GetFlags().Set(Stream::eBinary); + uint32_t count = 0; + lldb::Encoding encoding = Type::GetEncoding (clang_type, count); + + if (encoding == lldb::eEncodingInvalid || count != 1) + return false; + + uint64_t bit_width = ast_context->getTypeSize(qual_type); + // This function doesn't currently handle non-byte aligned assignments + if ((bit_width % 8) != 0) + return false; + + uint32_t byte_size = (bit_width + 7 ) / 8; + switch (encoding) + { + case lldb::eEncodingUint: + switch (byte_size) + { + case 1: strm.PutHex8(value.UInt()); return true; + case 2: strm.PutHex16(value.UInt()); return true; + case 4: strm.PutHex32(value.UInt()); return true; + case 8: strm.PutHex64(value.ULongLong()); return true; + default: + break; + } + break; + + case lldb::eEncodingSint: + switch (byte_size) + { + case 1: strm.PutHex8(value.SInt()); return true; + case 2: strm.PutHex16(value.SInt()); return true; + case 4: strm.PutHex32(value.SInt()); return true; + case 8: strm.PutHex64(value.SLongLong()); return true; + default: + break; + } + break; + + case lldb::eEncodingIEEE754: + if (byte_size <= sizeof(long double)) + { + if (byte_size == sizeof(float)) + { + strm.PutFloat(value.Float()); + return true; + } + else + if (byte_size == sizeof(double)) + { + strm.PutDouble(value.Double()); + return true; + } + else + if (byte_size == sizeof(long double)) + { + strm.PutDouble(value.LongDouble()); + return true; + } + } + break; + } + } + return false; +} + + +uint64_t +lldb_private::Type::GetByteSize() +{ + if (m_byte_size == 0) + { + switch (m_encoding_uid_type) + { + case eIsTypeWithUID: + case eIsConstTypeWithUID: + case eIsRestrictTypeWithUID: + case eIsVolatileTypeWithUID: + case eTypedefToTypeWithUID: + if (m_encoding_uid != LLDB_INVALID_UID) + { + Type *encoding_type = m_symbol_file->ResolveTypeUID (m_encoding_uid); + if (encoding_type) + m_byte_size = encoding_type->GetByteSize(); + } + if (m_byte_size == 0) + { + uint64_t bit_width = GetClangAST()->getTypeSize(clang::QualType::getFromOpaquePtr(GetOpaqueClangQualType())); + m_byte_size = (bit_width + 7 ) / 8; + } + break; + + // If we are a pointer or reference, then this is just a pointer size; + case ePointerToTypeWithUID: + case eLValueReferenceToTypeWithUID: + case eRValueReferenceToTypeWithUID: + m_byte_size = GetTypeList()->GetClangASTContext().GetPointerBitSize() / 8; + break; + } + } + return m_byte_size; +} + + +uint32_t +lldb_private::Type::GetNumChildren (bool omit_empty_base_classes) +{ + if (!ResolveClangType()) + return 0; + return ClangASTContext::GetNumChildren (m_clang_qual_type, omit_empty_base_classes); + +} + +bool +lldb_private::Type::IsAggregateType () +{ + if (ResolveClangType()) + return ClangASTContext::IsAggregateType (m_clang_qual_type); + return false; +} + +lldb::Format +lldb_private::Type::GetFormat () +{ + // Make sure we resolve our type if it already hasn't been. + if (!ResolveClangType()) + return lldb::eFormatInvalid; + return lldb_private::Type::GetFormat (m_clang_qual_type); +} + + +lldb::Format +lldb_private::Type::GetFormat (void *clang_type) +{ + clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type)); + + switch (qual_type->getTypeClass()) + { + case clang::Type::FunctionNoProto: + case clang::Type::FunctionProto: + break; + + case clang::Type::IncompleteArray: + case clang::Type::VariableArray: + break; + + case clang::Type::ConstantArray: + break; + + case clang::Type::ExtVector: + case clang::Type::Vector: + break; + + case clang::Type::Builtin: + switch (cast<clang::BuiltinType>(qual_type)->getKind()) + { + default: assert(0 && "Unknown builtin type!"); + case clang::BuiltinType::Void: + break; + + case clang::BuiltinType::Bool: return lldb::eFormatBoolean; + case clang::BuiltinType::Char_S: + case clang::BuiltinType::SChar: + case clang::BuiltinType::Char_U: + case clang::BuiltinType::UChar: + case clang::BuiltinType::WChar: return lldb::eFormatChar; + case clang::BuiltinType::Char16: return lldb::eFormatUnicode16; + case clang::BuiltinType::Char32: return lldb::eFormatUnicode32; + case clang::BuiltinType::UShort: return lldb::eFormatHex; + case clang::BuiltinType::Short: return lldb::eFormatDecimal; + case clang::BuiltinType::UInt: return lldb::eFormatHex; + case clang::BuiltinType::Int: return lldb::eFormatDecimal; + case clang::BuiltinType::ULong: return lldb::eFormatHex; + case clang::BuiltinType::Long: return lldb::eFormatDecimal; + case clang::BuiltinType::ULongLong: return lldb::eFormatHex; + case clang::BuiltinType::LongLong: return lldb::eFormatDecimal; + case clang::BuiltinType::UInt128: return lldb::eFormatHex; + case clang::BuiltinType::Int128: return lldb::eFormatDecimal; + case clang::BuiltinType::Float: return lldb::eFormatFloat; + case clang::BuiltinType::Double: return lldb::eFormatFloat; + case clang::BuiltinType::LongDouble: return lldb::eFormatFloat; + case clang::BuiltinType::NullPtr: return lldb::eFormatHex; + } + break; + case clang::Type::ObjCObjectPointer: return lldb::eFormatHex; + case clang::Type::BlockPointer: return lldb::eFormatHex; + case clang::Type::Pointer: return lldb::eFormatHex; + case clang::Type::LValueReference: + case clang::Type::RValueReference: return lldb::eFormatHex; + case clang::Type::MemberPointer: break; + case clang::Type::Complex: return lldb::eFormatComplex; + case clang::Type::ObjCInterface: break; + case clang::Type::Record: break; + case clang::Type::Enum: return lldb::eFormatEnum; + case clang::Type::Typedef: + return lldb_private::Type::GetFormat(cast<clang::TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr()); + + case clang::Type::TypeOfExpr: + case clang::Type::TypeOf: + case clang::Type::Decltype: +// case clang::Type::QualifiedName: + case clang::Type::TemplateSpecialization: break; + } + // We don't know hot to display this type... + return lldb::eFormatBytes; +} + + +lldb::Encoding +lldb_private::Type::GetEncoding (uint32_t &count) +{ + // Make sure we resolve our type if it already hasn't been. + if (!ResolveClangType()) + return lldb::eEncodingInvalid; + + return Type::GetEncoding (m_clang_qual_type, count); +} + + +lldb::Encoding +lldb_private::Type::GetEncoding (void *clang_type, uint32_t &count) +{ + count = 1; + clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type)); + + switch (qual_type->getTypeClass()) + { + case clang::Type::FunctionNoProto: + case clang::Type::FunctionProto: + break; + + case clang::Type::IncompleteArray: + case clang::Type::VariableArray: + break; + + case clang::Type::ConstantArray: + break; + + case clang::Type::ExtVector: + case clang::Type::Vector: + // TODO: Set this to more than one??? + break; + + case clang::Type::Builtin: + switch (cast<clang::BuiltinType>(qual_type)->getKind()) + { + default: assert(0 && "Unknown builtin type!"); + case clang::BuiltinType::Void: + break; + + case clang::BuiltinType::Bool: + case clang::BuiltinType::Char_S: + case clang::BuiltinType::SChar: + case clang::BuiltinType::WChar: + case clang::BuiltinType::Char16: + case clang::BuiltinType::Char32: + case clang::BuiltinType::Short: + case clang::BuiltinType::Int: + case clang::BuiltinType::Long: + case clang::BuiltinType::LongLong: + case clang::BuiltinType::Int128: return lldb::eEncodingSint; + + case clang::BuiltinType::Char_U: + case clang::BuiltinType::UChar: + case clang::BuiltinType::UShort: + case clang::BuiltinType::UInt: + case clang::BuiltinType::ULong: + case clang::BuiltinType::ULongLong: + case clang::BuiltinType::UInt128: return lldb::eEncodingUint; + + case clang::BuiltinType::Float: + case clang::BuiltinType::Double: + case clang::BuiltinType::LongDouble: return lldb::eEncodingIEEE754; + + case clang::BuiltinType::NullPtr: return lldb::eEncodingUint; + } + break; + // All pointer types are represented as unsigned integer encodings. + // We may nee to add a eEncodingPointer if we ever need to know the + // difference + case clang::Type::ObjCObjectPointer: + case clang::Type::BlockPointer: + case clang::Type::Pointer: + case clang::Type::LValueReference: + case clang::Type::RValueReference: + case clang::Type::MemberPointer: return lldb::eEncodingUint; + // Complex numbers are made up of floats + case clang::Type::Complex: + count = 2; + return lldb::eEncodingIEEE754; + + case clang::Type::ObjCInterface: break; + case clang::Type::Record: break; + case clang::Type::Enum: return lldb::eEncodingSint; + case clang::Type::Typedef: + return Type::GetEncoding(cast<clang::TypedefType>(qual_type)->LookThroughTypedefs().getAsOpaquePtr(), count); + break; + + case clang::Type::TypeOfExpr: + case clang::Type::TypeOf: + case clang::Type::Decltype: +// case clang::Type::QualifiedName: + case clang::Type::TemplateSpecialization: break; + } + count = 0; + return lldb::eEncodingInvalid; +} + + +bool +lldb_private::Type::DumpValueInMemory +( + lldb_private::ExecutionContext *exe_ctx, + lldb_private::Stream *s, + lldb::addr_t address, + lldb::AddressType address_type, + bool show_types, + bool show_summary, + bool verbose +) +{ + if (address != LLDB_INVALID_ADDRESS) + { + lldb_private::DataExtractor data; + data.SetByteOrder (exe_ctx->process->GetByteOrder()); + if (ReadFromMemory (exe_ctx, address, address_type, data)) + { + DumpValue(exe_ctx, s, data, 0, show_types, show_summary, verbose); + return true; + } + } + return false; +} + +bool +lldb_private::Type::ReadFromMemory +( + lldb_private::ExecutionContext *exe_ctx, + clang::ASTContext *ast_context, + void *clang_type, + lldb::addr_t addr, + lldb::AddressType address_type, + lldb_private::DataExtractor &data +) +{ + if (address_type == lldb::eAddressTypeFile) + { + // Can't convert a file address to anything valid without more + // context (which Module it came from) + return false; + } + clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type)); + + const uint32_t byte_size = (ast_context->getTypeSize (qual_type) + 7) / 8; + if (data.GetByteSize() < byte_size) + { + lldb::DataBufferSP data_sp(new DataBufferHeap (byte_size, '\0')); + data.SetData(data_sp); + } + + uint8_t* dst = (uint8_t*)data.PeekData(0, byte_size); + if (dst != NULL) + { + if (address_type == lldb::eAddressTypeHost) + { + // The address is an address in this process, so just copy it + memcpy (dst, (uint8_t*)NULL + addr, byte_size); + return true; + } + else + { + if (exe_ctx && exe_ctx->process) + { + Error error; + return exe_ctx->process->ReadMemory(addr, dst, byte_size, error) == byte_size; + } + } + } + return false; +} + +bool +lldb_private::Type::WriteToMemory +( + lldb_private::ExecutionContext *exe_ctx, + clang::ASTContext *ast_context, + void *clang_type, + lldb::addr_t addr, + lldb::AddressType address_type, + StreamString &new_value +) +{ + if (address_type == lldb::eAddressTypeFile) + { + // Can't convert a file address to anything valid without more + // context (which Module it came from) + return false; + } + clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type)); + const uint32_t byte_size = (ast_context->getTypeSize (qual_type) + 7) / 8; + + if (byte_size > 0) + { + if (address_type == lldb::eAddressTypeHost) + { + // The address is an address in this process, so just copy it + memcpy ((void *)addr, new_value.GetData(), byte_size); + return true; + } + else + { + if (exe_ctx && exe_ctx->process) + { + Error error; + return exe_ctx->process->WriteMemory(addr, new_value.GetData(), byte_size, error) == byte_size; + } + } + } + return false; +} + + +bool +lldb_private::Type::ReadFromMemory (lldb_private::ExecutionContext *exe_ctx, lldb::addr_t addr, lldb::AddressType address_type, lldb_private::DataExtractor &data) +{ + if (address_type == lldb::eAddressTypeFile) + { + // Can't convert a file address to anything valid without more + // context (which Module it came from) + return false; + } + + const uint32_t byte_size = GetByteSize(); + if (data.GetByteSize() < byte_size) + { + lldb::DataBufferSP data_sp(new DataBufferHeap (byte_size, '\0')); + data.SetData(data_sp); + } + + uint8_t* dst = (uint8_t*)data.PeekData(0, byte_size); + if (dst != NULL) + { + if (address_type == lldb::eAddressTypeHost) + { + // The address is an address in this process, so just copy it + memcpy (dst, (uint8_t*)NULL + addr, byte_size); + return true; + } + else + { + if (exe_ctx && exe_ctx->process) + { + Error error; + return exe_ctx->process->ReadMemory(addr, dst, byte_size, error) == byte_size; + } + } + } + return false; +} + + +bool +lldb_private::Type::WriteToMemory (lldb_private::ExecutionContext *exe_ctx, lldb::addr_t addr, lldb::AddressType address_type, lldb_private::DataExtractor &data) +{ + return false; +} + + +lldb_private::TypeList* +lldb_private::Type::GetTypeList() +{ + return GetSymbolFile()->GetObjectFile()->GetModule()->GetTypeList(); +} + + +bool +lldb_private::Type::ResolveClangType() +{ + clang::QualType qual_type(clang::QualType::getFromOpaquePtr(m_clang_qual_type)); + if (qual_type.getTypePtr() == NULL) + { + clang::QualType resolved_qual_type; + TypeList *type_list = GetTypeList(); + if (m_encoding_uid != LLDB_INVALID_UID) + { + Type *encoding_type = m_symbol_file->ResolveTypeUID(m_encoding_uid); + if (encoding_type) + { + + switch (m_encoding_uid_type) + { + case eIsTypeWithUID: + resolved_qual_type = clang::QualType::getFromOpaquePtr(encoding_type->GetOpaqueClangQualType()); + break; + + case eIsConstTypeWithUID: + resolved_qual_type = clang::QualType::getFromOpaquePtr(ClangASTContext::AddConstModifier (encoding_type->GetOpaqueClangQualType())); + break; + + case eIsRestrictTypeWithUID: + resolved_qual_type = clang::QualType::getFromOpaquePtr(ClangASTContext::AddRestrictModifier (encoding_type->GetOpaqueClangQualType())); + break; + + case eIsVolatileTypeWithUID: + resolved_qual_type = clang::QualType::getFromOpaquePtr(ClangASTContext::AddVolatileModifier (encoding_type->GetOpaqueClangQualType())); + break; + + case eTypedefToTypeWithUID: + resolved_qual_type = clang::QualType::getFromOpaquePtr(type_list->CreateClangTypedefType (this, encoding_type)); + // Clear the name so it can get fully qualified in case the + // typedef is in a namespace. + m_name.Clear(); + break; + + case ePointerToTypeWithUID: + resolved_qual_type = clang::QualType::getFromOpaquePtr(type_list->CreateClangPointerType (encoding_type)); + break; + + case eLValueReferenceToTypeWithUID: + resolved_qual_type = clang::QualType::getFromOpaquePtr(type_list->CreateClangLValueReferenceType (encoding_type)); + break; + + case eRValueReferenceToTypeWithUID: + resolved_qual_type = clang::QualType::getFromOpaquePtr(type_list->CreateClangRValueReferenceType (encoding_type)); + break; + + default: + assert(!"Unhandled encoding_uid_type."); + break; + } + } + } + else + { + // We have no encoding type, return void? + void *void_clang_type = type_list->GetClangASTContext().GetVoidBuiltInType(); + switch (m_encoding_uid_type) + { + case eIsTypeWithUID: + resolved_qual_type = clang::QualType::getFromOpaquePtr(void_clang_type); + break; + + case eIsConstTypeWithUID: + resolved_qual_type = clang::QualType::getFromOpaquePtr (ClangASTContext::AddConstModifier (void_clang_type)); + break; + + case eIsRestrictTypeWithUID: + resolved_qual_type = clang::QualType::getFromOpaquePtr (ClangASTContext::AddRestrictModifier (void_clang_type)); + break; + + case eIsVolatileTypeWithUID: + resolved_qual_type = clang::QualType::getFromOpaquePtr (ClangASTContext::AddVolatileModifier (void_clang_type)); + break; + + case eTypedefToTypeWithUID: + resolved_qual_type = clang::QualType::getFromOpaquePtr(type_list->GetClangASTContext().CreateTypedefType (m_name.AsCString(), void_clang_type, NULL)); + break; + + case ePointerToTypeWithUID: + resolved_qual_type = clang::QualType::getFromOpaquePtr(type_list->GetClangASTContext().CreatePointerType (void_clang_type)); + break; + + case eLValueReferenceToTypeWithUID: + resolved_qual_type = clang::QualType::getFromOpaquePtr(type_list->GetClangASTContext().CreateLValueReferenceType (void_clang_type)); + break; + + case eRValueReferenceToTypeWithUID: + resolved_qual_type = clang::QualType::getFromOpaquePtr(type_list->GetClangASTContext().CreateRValueReferenceType (void_clang_type)); + break; + + default: + assert(!"Unhandled encoding_uid_type."); + break; + } + } + if (resolved_qual_type.getTypePtr()) + { + m_clang_qual_type = resolved_qual_type.getAsOpaquePtr(); + } + + } + return m_clang_qual_type != NULL; +} + +void * +lldb_private::Type::GetChildClangTypeAtIndex +( + const char *parent_name, + uint32_t idx, + bool transparent_pointers, + bool omit_empty_base_classes, + ConstString& name, + uint32_t &child_byte_size, + int32_t &child_byte_offset, + uint32_t &child_bitfield_bit_size, + uint32_t &child_bitfield_bit_offset +) +{ + if (!ResolveClangType()) + return false; + + std::string name_str; + void *child_qual_type = GetClangASTContext().GetChildClangTypeAtIndex ( + parent_name, + m_clang_qual_type, + idx, + transparent_pointers, + omit_empty_base_classes, + name_str, + child_byte_size, + child_byte_offset, + child_bitfield_bit_size, + child_bitfield_bit_offset); + + if (child_qual_type) + { + if (!name_str.empty()) + name.SetCString(name_str.c_str()); + else + name.Clear(); + } + return child_qual_type; +} + + + +void * +lldb_private::Type::GetOpaqueClangQualType () +{ + ResolveClangType(); + return m_clang_qual_type; +} + +clang::ASTContext * +lldb_private::Type::GetClangAST () +{ + TypeList *type_list = GetTypeList(); + if (type_list) + return type_list->GetClangASTContext().getASTContext(); + return NULL; +} + +lldb_private::ClangASTContext & +lldb_private::Type::GetClangASTContext () +{ + return GetTypeList()->GetClangASTContext(); +} + +int +lldb_private::Type::Compare(const Type &a, const Type &b) +{ + // Just compare the UID values for now... + lldb::user_id_t a_uid = a.GetID(); + lldb::user_id_t b_uid = b.GetID(); + if (a_uid < b_uid) + return -1; + if (a_uid > b_uid) + return 1; + return 0; +// if (a.getQualType() == b.getQualType()) +// return 0; +} + diff --git a/lldb/source/Symbol/TypeList.cpp b/lldb/source/Symbol/TypeList.cpp new file mode 100644 index 00000000000..f037035ed21 --- /dev/null +++ b/lldb/source/Symbol/TypeList.cpp @@ -0,0 +1,239 @@ +//===-- TypeList.cpp --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +// C Includes +// C++ Includes +#include <vector> + +// Other libraries and framework includes +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclGroup.h" + +#include "clang/Basic/Builtins.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" + +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/raw_ostream.h" + +// Project includes +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/SymbolFile.h" +#include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Symbol/Type.h" +#include "lldb/Symbol/TypeList.h" + +using namespace lldb; +using namespace lldb_private; +using namespace clang; + +TypeList::TypeList(const char *target_triple) : + m_types(), + m_ast(target_triple) +{ +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +TypeList::~TypeList() +{ +} + +//---------------------------------------------------------------------- +// Add a base type to the type list +//---------------------------------------------------------------------- + +//struct CampareDCTypeBaton +//{ +// CampareDCTypeBaton(const std::vector<TypeSP>& _types, const Type* _search_type) : +// types(_types), +// search_type(_search_type) +// { +// } +// const std::vector<TypeSP>& types; +// const Type* search_type; +//}; +// +//static int +//compare_dc_type (const void *key, const void *arrmem) +//{ +// const Type* search_type = ((CampareDCTypeBaton*) key)->search_type; +// uint32_t curr_index = *(uint32_t *)arrmem; +// const Type* curr_type = ((CampareDCTypeBaton*) key)->types[curr_index].get(); +// Type::CompareState state; +// return Type::Compare(*search_type, *curr_type, state); +//} +// +//struct LessThanBinaryPredicate +//{ +// LessThanBinaryPredicate(const CampareDCTypeBaton& _compare_baton) : +// compare_baton(_compare_baton) +// { +// } +// +// bool operator() (uint32_t a, uint32_t b) const +// { +// Type::CompareState state; +// return Type::Compare(*compare_baton.search_type, *compare_baton.types[b].get(), state) < 0; +// } +// const CampareDCTypeBaton& compare_baton; +//}; + +TypeSP +TypeList::InsertUnique(TypeSP& type_sp) +{ +#if 0 +// Stream s(stdout); +// s << "TypeList::InsertUnique for type "; +// type_sp->Dump(s); +// s << "Current list:\n"; +// Dump(s); + + CampareDCTypeBaton compare_baton(m_types, type_sp.get()); + uint32_t* match_index_ptr = (uint32_t*)bsearch(&compare_baton, &m_sorted_indexes[0], m_sorted_indexes.size(), sizeof(uint32_t), compare_dc_type); + if (match_index_ptr) + { +// s << "returning existing type: " << (void *)m_types[*match_index_ptr].get() << "\n"; + return m_types[*match_index_ptr]; + } + + // Get the new index within the m_types array before we add the new type + uint32_t uniqued_type_index = m_types.size(); + // Add the new shared pointer to our type by appending it to the end of the types array + m_types.push_back(type_sp); + // Figure out what the sorted index of this new type should be + uint32_t fake_index = 0; + LessThanBinaryPredicate compare_func_obj(compare_baton); + std::vector<uint32_t>::iterator insert_pos = std::upper_bound(m_sorted_indexes.begin(), m_sorted_indexes.end(), fake_index, compare_func_obj); + // Insert the sorted index into our sorted index array + m_sorted_indexes.insert(insert_pos, uniqued_type_index); +#else + // Just push each type on the back for now. We will worry about uniquing later + m_types.push_back (type_sp); +#endif +// s << "New list:\n"; +// Dump(s); + + return type_sp; +} + +//---------------------------------------------------------------------- +// Find a base type by its unique ID. +//---------------------------------------------------------------------- +TypeSP +TypeList::FindType(lldb::user_id_t uid) +{ + TypeSP type_sp; + iterator pos, end; + for (pos = m_types.begin(), end = m_types.end(); pos != end; ++pos) + if ((*pos)->GetID() == uid) + return *pos; + + return type_sp; +} + +//---------------------------------------------------------------------- +// Find a type by name. +//---------------------------------------------------------------------- +TypeList +TypeList::FindTypes(const ConstString &name) +{ + TypeList types(m_ast.getTargetInfo()->getTriple().getTriple().c_str()); + iterator pos, end; + for (pos = m_types.begin(), end = m_types.end(); pos != end; ++pos) + if ((*pos)->GetName() == name) + types.InsertUnique(*pos); + return types; +} + +void +TypeList::Clear() +{ + m_types.clear(); +} + +uint32_t +TypeList::GetSize() const +{ + return m_types.size(); +} + +TypeSP +TypeList::GetTypeAtIndex(uint32_t idx) +{ + TypeSP type_sp; + if (idx < m_types.size()) + type_sp = m_types[idx]; + return type_sp; +} + +void +TypeList::Dump(Stream *s, bool show_context) +{ +// std::vector<uint32_t>::const_iterator pos, end; +// for (pos = end = m_sorted_indexes.begin(), end = m_sorted_indexes.end(); pos != end; ++pos) +// { +// m_types[*pos]->Dump(s, show_context); +// } + + m_ast.getASTContext()->getTranslationUnitDecl()->print(llvm::fouts(), 0); + const size_t num_types = m_types.size(); + for (size_t i=0; i<num_types; ++i) + { + m_types[i]->Dump(s, show_context); + } +// ASTContext *ast_context = GetClangASTContext ().getASTContext(); +// if (ast_context) +// ast_context->PrintStats(); +} + + +ClangASTContext & +TypeList::GetClangASTContext () +{ + return m_ast; +} + +void * +TypeList::CreateClangPointerType (Type *type) +{ + assert(type); + return m_ast.CreatePointerType(type->GetOpaqueClangQualType()); +} + +void * +TypeList::CreateClangTypedefType (Type *typedef_type, Type *base_type) +{ + assert(typedef_type && base_type); + return m_ast.CreateTypedefType(typedef_type->GetName().AsCString(), base_type->GetOpaqueClangQualType(), typedef_type->GetSymbolFile()->GetClangDeclContextForTypeUID(typedef_type->GetID())); +} + +void * +TypeList::CreateClangLValueReferenceType (Type *type) +{ + assert(type); + return m_ast.CreateLValueReferenceType(type->GetOpaqueClangQualType()); +} + +void * +TypeList::CreateClangRValueReferenceType (Type *type) +{ + assert(type); + return m_ast.CreateRValueReferenceType (type->GetOpaqueClangQualType()); +} + + + diff --git a/lldb/source/Symbol/Variable.cpp b/lldb/source/Symbol/Variable.cpp new file mode 100644 index 00000000000..35dcabfdd59 --- /dev/null +++ b/lldb/source/Symbol/Variable.cpp @@ -0,0 +1,167 @@ +//===-- Variable.cpp --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Symbol/Variable.h" + +#include "lldb/Core/Stream.h" +#include "lldb/Symbol/Block.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Symbol/Type.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Thread.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// Variable constructor +//---------------------------------------------------------------------- +Variable::Variable(lldb::user_id_t uid, + const ConstString& name, + Type *type, + ValueType scope, + SymbolContextScope *context, + Declaration* decl_ptr, + const DWARFExpression& location, + bool external, + bool artificial) : + UserID(uid), + m_name(name), + m_type(type), + m_scope(scope), + m_context(context), + m_declaration(decl_ptr), + m_location(location), + m_external(external), + m_artificial(artificial) +{ +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +Variable::~Variable() +{ +} + + +void +Variable::Dump(Stream *s, bool show_context) const +{ + s->Printf("%.*p: ", (int)sizeof(void*) * 2, this); + s->Indent(); + *s << "Variable" << (const UserID&)*this; + + if (m_name) + *s << ", name = \"" << m_name << "\""; + + if (m_type != NULL) + { + *s << ", type = " << (void*)m_type << " ("; + m_type->DumpTypeName(s); + s->PutChar(')'); + } + + if (m_scope != eValueTypeInvalid) + { + s->PutCString(", scope = "); + switch (m_scope) + { + case eValueTypeVariableGlobal: s->PutCString(m_external ? "global" : "static"); break; + case eValueTypeVariableArgument: s->PutCString("parameter"); break; + case eValueTypeVariableLocal: s->PutCString("local"); break; + default: *s << "??? (" << m_scope << ')'; + } + } + + if (show_context && m_context != NULL) + { + s->PutCString(", context = ( "); + m_context->DumpSymbolContext(s); + s->PutCString(" )"); + } + + m_declaration.Dump(s); + + if (m_location.IsValid()) + { + s->PutCString(", location = "); + m_location.GetDescription(s, lldb::eDescriptionLevelBrief); + } + + if (m_external) + s->PutCString(", external"); + + if (m_artificial) + s->PutCString(", artificial"); + + s->EOL(); +} + + +size_t +Variable::MemorySize() const +{ + return sizeof(Variable); +} + + +void +Variable::CalculateSymbolContext (SymbolContext *sc) +{ + if (m_context) + m_context->CalculateSymbolContext(sc); + else + sc->Clear(); +} + + +bool +Variable::IsInScope (StackFrame *frame) +{ + switch (m_scope) + { + case eValueTypeVariableGlobal: + // Globals and statics are always in scope. + return true; + + case eValueTypeVariableArgument: + case eValueTypeVariableLocal: + // Check if the location has a location list that describes the value + // of the variable with address ranges and different locations for each + // address range? + if (m_location.IsLocationList()) + { + // It is a location list. We just need to tell if the location + // list contains the current address when converted to a load + // address + return m_location.LocationListContainsLoadAddress (&frame->GetThread().GetProcess(), frame->GetPC()); + } + else + { + // We don't have a location list, we just need to see if the block + // that this variable was defined in is currently + Block *frame_block = frame->GetSymbolContext(eSymbolContextBlock).block; + if (frame_block) + { + SymbolContext variable_sc; + CalculateSymbolContext (&variable_sc); + if (variable_sc.function && variable_sc.block) + return variable_sc.block->ContainsBlockWithID (frame_block->GetID()); + } + } + break; + + default: + break; + } + return false; +} + diff --git a/lldb/source/Symbol/VariableList.cpp b/lldb/source/Symbol/VariableList.cpp new file mode 100644 index 00000000000..7f864f287ea --- /dev/null +++ b/lldb/source/Symbol/VariableList.cpp @@ -0,0 +1,116 @@ +//===-- VariableList.cpp ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Symbol/VariableList.h" +#include "lldb/Symbol/Block.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/CompileUnit.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// VariableList constructor +//---------------------------------------------------------------------- +VariableList::VariableList() : + m_variables() +{ +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +VariableList::~VariableList() +{ +} + + +void +VariableList::AddVariable(VariableSP &variable_sp) +{ + m_variables.push_back(variable_sp); +} + + +void +VariableList::AddVariables(VariableList *variable_list) +{ + std::copy( variable_list->m_variables.begin(), // source begin + variable_list->m_variables.end(), // source end + back_inserter(m_variables)); // destination +} + + +void +VariableList::Clear() +{ + m_variables.clear(); +} + + + +VariableSP +VariableList::GetVariableAtIndex(uint32_t idx) +{ + VariableSP variable_sp; + if (idx < m_variables.size()) + variable_sp = m_variables[idx]; + return variable_sp; +} + + + +VariableSP +VariableList::FindVariable(const ConstString& name) +{ + VariableSP var_sp; + iterator pos, end = m_variables.end(); + for (pos = m_variables.begin(); pos != end; ++pos) + { + if ((*pos)->GetName() == name) + { + var_sp = (*pos); + break; + } + } + return var_sp; +} + + +size_t +VariableList::MemorySize() const +{ + size_t mem_size = sizeof(VariableList); + const_iterator pos, end = m_variables.end(); + for (pos = m_variables.begin(); pos != end; ++pos) + mem_size += (*pos)->MemorySize(); + return mem_size; +} + +size_t +VariableList::GetSize() const +{ + return m_variables.size(); +} + + +void +VariableList::Dump(Stream *s, bool show_context) const +{ +// s.Printf("%.*p: ", (int)sizeof(void*) * 2, this); +// s.Indent(); +// s << "VariableList\n"; + + const_iterator pos, end = m_variables.end(); + for (pos = m_variables.begin(); pos != end; ++pos) + { + (*pos)->Dump(s, show_context); + } +} + |