summaryrefslogtreecommitdiffstats
path: root/lldb/source/Symbol
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Symbol')
-rw-r--r--lldb/source/Symbol/Block.cpp641
-rw-r--r--lldb/source/Symbol/ClangASTContext.cpp2552
-rw-r--r--lldb/source/Symbol/CompileUnit.cpp366
-rw-r--r--lldb/source/Symbol/DWARFCallFrameInfo.cpp1344
-rw-r--r--lldb/source/Symbol/Declaration.cpp172
-rw-r--r--lldb/source/Symbol/Function.cpp432
-rw-r--r--lldb/source/Symbol/LineEntry.cpp237
-rw-r--r--lldb/source/Symbol/LineTable.cpp332
-rw-r--r--lldb/source/Symbol/ObjectFile.cpp92
-rw-r--r--lldb/source/Symbol/Symbol.cpp463
-rw-r--r--lldb/source/Symbol/SymbolContext.cpp424
-rw-r--r--lldb/source/Symbol/SymbolFile.cpp50
-rw-r--r--lldb/source/Symbol/SymbolVendor.mm386
-rw-r--r--lldb/source/Symbol/Symtab.cpp596
-rw-r--r--lldb/source/Symbol/Type.cpp1531
-rw-r--r--lldb/source/Symbol/TypeList.cpp239
-rw-r--r--lldb/source/Symbol/Variable.cpp167
-rw-r--r--lldb/source/Symbol/VariableList.cpp116
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 &regexp, 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 &regex, 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);
+ }
+}
+
OpenPOWER on IntegriCloud