Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@@ -0,0 +1,371 @@
//===-- ArmUnwindInfo.cpp ---------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <vector>
#include "Utility/ARM_DWARF_Registers.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Section.h"
#include "lldb/Symbol/ArmUnwindInfo.h"
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Utility/Endian.h"
/*
* Unwind information reader and parser for the ARM exception handling ABI
*
* Implemented based on:
* Exception Handling ABI for the ARM Architecture
* Document number: ARM IHI 0038A (current through ABI r2.09)
* Date of Issue: 25th January 2007, reissued 30th November 2012
* http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038a/IHI0038A_ehabi.pdf
*/
using namespace lldb;
using namespace lldb_private;
// Converts a prel31 avlue to lldb::addr_t with sign extension
static addr_t Prel31ToAddr(uint32_t prel31) {
addr_t res = prel31;
if (prel31 & (1 << 30))
res |= 0xffffffff80000000ULL;
return res;
}
ArmUnwindInfo::ArmExidxEntry::ArmExidxEntry(uint32_t f, lldb::addr_t a,
uint32_t d)
: file_address(f), address(a), data(d) {}
bool ArmUnwindInfo::ArmExidxEntry::operator<(const ArmExidxEntry &other) const {
return address < other.address;
}
ArmUnwindInfo::ArmUnwindInfo(ObjectFile &objfile, SectionSP &arm_exidx,
SectionSP &arm_extab)
: m_byte_order(objfile.GetByteOrder()), m_arm_exidx_sp(arm_exidx),
m_arm_extab_sp(arm_extab) {
objfile.ReadSectionData(arm_exidx.get(), m_arm_exidx_data);
objfile.ReadSectionData(arm_extab.get(), m_arm_extab_data);
addr_t exidx_base_addr = m_arm_exidx_sp->GetFileAddress();
offset_t offset = 0;
while (m_arm_exidx_data.ValidOffset(offset)) {
lldb::addr_t file_addr = exidx_base_addr + offset;
lldb::addr_t addr = exidx_base_addr + (addr_t)offset +
Prel31ToAddr(m_arm_exidx_data.GetU32(&offset));
uint32_t data = m_arm_exidx_data.GetU32(&offset);
m_exidx_entries.emplace_back(file_addr, addr, data);
}
// Sort the entries in the exidx section. The entries should be sorted inside
// the section but
// some old compiler isn't sorted them.
std::sort(m_exidx_entries.begin(), m_exidx_entries.end());
}
ArmUnwindInfo::~ArmUnwindInfo() {}
// Read a byte from the unwind instruction stream with the given offset.
// Custom function is required because have to red in order of significance
// within their containing
// word (most significant byte first) and in increasing word address order.
uint8_t ArmUnwindInfo::GetByteAtOffset(const uint32_t *data,
uint16_t offset) const {
uint32_t value = data[offset / 4];
if (m_byte_order != endian::InlHostByteOrder())
value = llvm::ByteSwap_32(value);
return (value >> ((3 - (offset % 4)) * 8)) & 0xff;
}
uint64_t ArmUnwindInfo::GetULEB128(const uint32_t *data, uint16_t &offset,
uint16_t max_offset) const {
uint64_t result = 0;
uint8_t shift = 0;
while (offset < max_offset) {
uint8_t byte = GetByteAtOffset(data, offset++);
result |= (uint64_t)(byte & 0x7f) << shift;
if ((byte & 0x80) == 0)
break;
shift += 7;
}
return result;
}
bool ArmUnwindInfo::GetUnwindPlan(Target &target, const Address &addr,
UnwindPlan &unwind_plan) {
const uint32_t *data = (const uint32_t *)GetExceptionHandlingTableEntry(addr);
if (data == nullptr)
return false; // No unwind information for the function
if (data[0] == 0x1)
return false; // EXIDX_CANTUNWIND
uint16_t byte_count = 0;
uint16_t byte_offset = 0;
if (data[0] & 0x80000000) {
switch ((data[0] >> 24) & 0x0f) {
case 0:
byte_count = 4;
byte_offset = 1;
break;
case 1:
case 2:
byte_count = 4 * ((data[0] >> 16) & 0xff) + 4;
byte_offset = 2;
break;
default:
// Unhandled personality routine index
return false;
}
} else {
byte_count = 4 * ((data[1] >> 24) & 0xff) + 8;
byte_offset = 5;
}
uint8_t vsp_reg = dwarf_sp;
int32_t vsp = 0;
std::vector<std::pair<uint32_t, int32_t>>
register_offsets; // register -> (offset from vsp_reg)
while (byte_offset < byte_count) {
uint8_t byte1 = GetByteAtOffset(data, byte_offset++);
if ((byte1 & 0xc0) == 0x00) {
// 00xxxxxx
// vsp = vsp + (xxxxxx << 2) + 4. Covers range 0x04-0x100 inclusive
vsp += ((byte1 & 0x3f) << 2) + 4;
} else if ((byte1 & 0xc0) == 0x40) {
// 01xxxxxx
// vsp = vsp – (xxxxxx << 2) - 4. Covers range 0x04-0x100 inclusive
vsp -= ((byte1 & 0x3f) << 2) + 4;
} else if ((byte1 & 0xf0) == 0x80) {
if (byte_offset >= byte_count)
return false;
uint8_t byte2 = GetByteAtOffset(data, byte_offset++);
if (byte1 == 0x80 && byte2 == 0) {
// 10000000 00000000
// Refuse to unwind (for example, out of a cleanup) (see remark a)
return false;
} else {
// 1000iiii iiiiiiii (i not all 0)
// Pop up to 12 integer registers under masks {r15-r12}, {r11-r4} (see
// remark b)
uint16_t regs = ((byte1 & 0x0f) << 8) | byte2;
for (uint8_t i = 0; i < 12; ++i) {
if (regs & (1 << i)) {
register_offsets.emplace_back(dwarf_r4 + i, vsp);
vsp += 4;
}
}
}
} else if ((byte1 & 0xff) == 0x9d) {
// 10011101
// Reserved as prefix for ARM register to register moves
return false;
} else if ((byte1 & 0xff) == 0x9f) {
// 10011111
// Reserved as prefix for Intel Wireless MMX register to register moves
return false;
} else if ((byte1 & 0xf0) == 0x90) {
// 1001nnnn (nnnn != 13,15)
// Set vsp = r[nnnn]
vsp_reg = dwarf_r0 + (byte1 & 0x0f);
} else if ((byte1 & 0xf8) == 0xa0) {
// 10100nnn
// Pop r4-r[4+nnn]
uint8_t n = byte1 & 0x7;
for (uint8_t i = 0; i <= n; ++i) {
register_offsets.emplace_back(dwarf_r4 + i, vsp);
vsp += 4;
}
} else if ((byte1 & 0xf8) == 0xa8) {
// 10101nnn
// Pop r4-r[4+nnn], r14
uint8_t n = byte1 & 0x7;
for (uint8_t i = 0; i <= n; ++i) {
register_offsets.emplace_back(dwarf_r4 + i, vsp);
vsp += 4;
}
register_offsets.emplace_back(dwarf_lr, vsp);
vsp += 4;
} else if ((byte1 & 0xff) == 0xb0) {
// 10110000
// Finish (see remark c)
break;
} else if ((byte1 & 0xff) == 0xb1) {
if (byte_offset >= byte_count)
return false;
uint8_t byte2 = GetByteAtOffset(data, byte_offset++);
if ((byte2 & 0xff) == 0x00) {
// 10110001 00000000
// Spare (see remark f)
return false;
} else if ((byte2 & 0xf0) == 0x00) {
// 10110001 0000iiii (i not all 0)
// Pop integer registers under mask {r3, r2, r1, r0}
for (uint8_t i = 0; i < 4; ++i) {
if (byte2 & (1 << i)) {
register_offsets.emplace_back(dwarf_r0 + i, vsp);
vsp += 4;
}
}
} else {
// 10110001 xxxxyyyy
// Spare (xxxx != 0000)
return false;
}
} else if ((byte1 & 0xff) == 0xb2) {
// 10110010 uleb128
// vsp = vsp + 0x204+ (uleb128 << 2)
uint64_t uleb128 = GetULEB128(data, byte_offset, byte_count);
vsp += 0x204 + (uleb128 << 2);
} else if ((byte1 & 0xff) == 0xb3) {
// 10110011 sssscccc
// Pop VFP double-precision registers D[ssss]-D[ssss+cccc] saved (as if)
// by FSTMFDX (see remark d)
if (byte_offset >= byte_count)
return false;
uint8_t byte2 = GetByteAtOffset(data, byte_offset++);
uint8_t s = (byte2 & 0xf0) >> 4;
uint8_t c = (byte2 & 0x0f) >> 0;
for (uint8_t i = 0; i <= c; ++i) {
register_offsets.emplace_back(dwarf_d0 + s + i, vsp);
vsp += 8;
}
vsp += 4;
} else if ((byte1 & 0xfc) == 0xb4) {
// 101101nn
// Spare (was Pop FPA)
return false;
} else if ((byte1 & 0xf8) == 0xb8) {
// 10111nnn
// Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by
// FSTMFDX (see remark d)
uint8_t n = byte1 & 0x07;
for (uint8_t i = 0; i <= n; ++i) {
register_offsets.emplace_back(dwarf_d8 + i, vsp);
vsp += 8;
}
vsp += 4;
} else if ((byte1 & 0xf8) == 0xc0) {
// 11000nnn (nnn != 6,7)
// Intel Wireless MMX pop wR[10]-wR[10+nnn]
// 11000110 sssscccc
// Intel Wireless MMX pop wR[ssss]-wR[ssss+cccc] (see remark e)
// 11000111 00000000
// Spare
// 11000111 0000iiii
// Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0}
// 11000111 xxxxyyyy
// Spare (xxxx != 0000)
return false;
} else if ((byte1 & 0xff) == 0xc8) {
// 11001000 sssscccc
// Pop VFP double precision registers D[16+ssss]-D[16+ssss+cccc] saved (as
// if) by FSTMFDD (see remarks d,e)
if (byte_offset >= byte_count)
return false;
uint8_t byte2 = GetByteAtOffset(data, byte_offset++);
uint8_t s = (byte2 & 0xf0) >> 4;
uint8_t c = (byte2 & 0x0f) >> 0;
for (uint8_t i = 0; i <= c; ++i) {
register_offsets.emplace_back(dwarf_d16 + s + i, vsp);
vsp += 8;
}
} else if ((byte1 & 0xff) == 0xc9) {
// 11001001 sssscccc
// Pop VFP double precision registers D[ssss]-D[ssss+cccc] saved (as if)
// by FSTMFDD (see remark d)
if (byte_offset >= byte_count)
return false;
uint8_t byte2 = GetByteAtOffset(data, byte_offset++);
uint8_t s = (byte2 & 0xf0) >> 4;
uint8_t c = (byte2 & 0x0f) >> 0;
for (uint8_t i = 0; i <= c; ++i) {
register_offsets.emplace_back(dwarf_d0 + s + i, vsp);
vsp += 8;
}
} else if ((byte1 & 0xf8) == 0xc8) {
// 11001yyy
// Spare (yyy != 000, 001)
return false;
} else if ((byte1 & 0xf8) == 0xc0) {
// 11010nnn
// Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by
// FSTMFDD (see remark d)
uint8_t n = byte1 & 0x07;
for (uint8_t i = 0; i <= n; ++i) {
register_offsets.emplace_back(dwarf_d8 + i, vsp);
vsp += 8;
}
} else if ((byte1 & 0xc0) == 0xc0) {
// 11xxxyyy Spare (xxx != 000, 001, 010)
return false;
} else {
return false;
}
}
UnwindPlan::RowSP row = std::make_shared<UnwindPlan::Row>();
row->SetOffset(0);
row->GetCFAValue().SetIsRegisterPlusOffset(vsp_reg, vsp);
bool have_location_for_pc = false;
for (const auto &offset : register_offsets) {
have_location_for_pc |= offset.first == dwarf_pc;
row->SetRegisterLocationToAtCFAPlusOffset(offset.first, offset.second - vsp,
true);
}
if (!have_location_for_pc) {
UnwindPlan::Row::RegisterLocation lr_location;
if (row->GetRegisterInfo(dwarf_lr, lr_location))
row->SetRegisterInfo(dwarf_pc, lr_location);
else
row->SetRegisterLocationToRegister(dwarf_pc, dwarf_lr, false);
}
unwind_plan.AppendRow(row);
unwind_plan.SetSourceName("ARM.exidx unwind info");
unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
unwind_plan.SetRegisterKind(eRegisterKindDWARF);
return true;
}
const uint8_t *
ArmUnwindInfo::GetExceptionHandlingTableEntry(const Address &addr) {
auto it = std::upper_bound(m_exidx_entries.begin(), m_exidx_entries.end(),
ArmExidxEntry{0, addr.GetFileAddress(), 0});
if (it == m_exidx_entries.begin())
return nullptr;
--it;
if (it->data == 0x1)
return nullptr; // EXIDX_CANTUNWIND
if (it->data & 0x80000000)
return (const uint8_t *)&it->data;
addr_t data_file_addr = it->file_address + 4 + Prel31ToAddr(it->data);
return m_arm_extab_data.GetDataStart() +
(data_file_addr - m_arm_extab_sp->GetFileAddress());
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,59 @@
add_lldb_library(lldbSymbol
ArmUnwindInfo.cpp
Block.cpp
ClangASTContext.cpp
ClangASTImporter.cpp
ClangExternalASTSourceCallbacks.cpp
ClangExternalASTSourceCommon.cpp
ClangUtil.cpp
CompilerDecl.cpp
CompilerDeclContext.cpp
CompilerType.cpp
CompileUnit.cpp
CompactUnwindInfo.cpp
DebugMacros.cpp
Declaration.cpp
DWARFCallFrameInfo.cpp
Function.cpp
FuncUnwinders.cpp
GoASTContext.cpp
JavaASTContext.cpp
LineEntry.cpp
LineTable.cpp
ObjectFile.cpp
OCamlASTContext.cpp
Symbol.cpp
SymbolContext.cpp
SymbolFile.cpp
SymbolVendor.cpp
Symtab.cpp
Type.cpp
TypeList.cpp
TypeMap.cpp
TypeSystem.cpp
UnwindPlan.cpp
UnwindTable.cpp
Variable.cpp
VariableList.cpp
VerifyDecl.cpp
LINK_LIBS
clangAST
clangBasic
clangFrontend
lldbCore
lldbExpression
lldbHost
lldbTarget
lldbUtility
lldbPluginExpressionParserClang
lldbPluginExpressionParserGo
lldbPluginSymbolFileDWARF
lldbPluginSymbolFilePDB
lldbPluginObjectContainerBSDArchive
lldbPluginCPlusPlusLanguage
lldbPluginObjCLanguage
LINK_COMPONENTS
Support
)

View File

@@ -0,0 +1 @@
673124cc0de5f81cc2fae30985a6f1cde46ffef9

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,103 @@
//===-- ClangExternalASTSourceCallbacks.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/ClangExternalASTSourceCallbacks.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Clang headers like to use NDEBUG inside of them to enable/disable debug
// related features using "#ifndef NDEBUG" preprocessor blocks to do one thing
// or another. This is bad because it means that if clang was built in release
// mode, it assumes that you are building in release mode which is not always
// the case. You can end up with functions that are defined as empty in header
// files when NDEBUG is not defined, and this can cause link errors with the
// clang .a files that you have since you might be missing functions in the .a
// file. So we have to define NDEBUG when including clang headers to avoid any
// mismatches. This is covered by rdar://problem/8691220
#if !defined(NDEBUG) && !defined(LLVM_NDEBUG_OFF)
#define LLDB_DEFINED_NDEBUG_FOR_CLANG
#define NDEBUG
// Need to include assert.h so it is as clang would expect it to be (disabled)
#include <assert.h>
#endif
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclarationName.h"
#ifdef LLDB_DEFINED_NDEBUG_FOR_CLANG
#undef NDEBUG
#undef LLDB_DEFINED_NDEBUG_FOR_CLANG
// Need to re-include assert.h so it is as _we_ would expect it to be (enabled)
#include <assert.h>
#endif
#include "lldb/Utility/Log.h"
#include "clang/AST/Decl.h"
using namespace clang;
using namespace lldb_private;
bool ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(
const clang::DeclContext *decl_ctx,
clang::DeclarationName clang_decl_name) {
if (m_callback_find_by_name) {
llvm::SmallVector<clang::NamedDecl *, 3> results;
m_callback_find_by_name(m_callback_baton, decl_ctx, clang_decl_name,
&results);
SetExternalVisibleDeclsForName(decl_ctx, clang_decl_name, results);
return (results.size() != 0);
}
std::string decl_name(clang_decl_name.getAsString());
SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
return false;
}
void ClangExternalASTSourceCallbacks::CompleteType(TagDecl *tag_decl) {
if (m_callback_tag_decl)
m_callback_tag_decl(m_callback_baton, tag_decl);
}
void ClangExternalASTSourceCallbacks::CompleteType(
ObjCInterfaceDecl *objc_decl) {
if (m_callback_objc_decl)
m_callback_objc_decl(m_callback_baton, objc_decl);
}
bool ClangExternalASTSourceCallbacks::layoutRecordType(
const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,
llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets,
llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
&VirtualBaseOffsets) {
if (m_callback_layout_record_type)
return m_callback_layout_record_type(m_callback_baton, Record, Size,
Alignment, FieldOffsets, BaseOffsets,
VirtualBaseOffsets);
return false;
}
void ClangExternalASTSourceCallbacks::FindExternalLexicalDecls(
const clang::DeclContext *decl_ctx,
llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant,
llvm::SmallVectorImpl<clang::Decl *> &decls) {
if (m_callback_tag_decl && decl_ctx) {
clang::TagDecl *tag_decl = llvm::dyn_cast<clang::TagDecl>(
const_cast<clang::DeclContext *>(decl_ctx));
if (tag_decl)
CompleteType(tag_decl);
}
}

View File

@@ -0,0 +1,100 @@
//===-- ClangExternalASTSourceCommon.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/ClangExternalASTSourceCommon.h"
#include "lldb/Utility/Stream.h"
#include <mutex>
using namespace lldb_private;
uint64_t g_TotalSizeOfMetadata = 0;
typedef llvm::DenseMap<clang::ExternalASTSource *,
ClangExternalASTSourceCommon *>
ASTSourceMap;
static ASTSourceMap &GetSourceMap(std::unique_lock<std::mutex> &guard) {
// Intentionally leaked to avoid problems with global destructors.
static ASTSourceMap *s_source_map = new ASTSourceMap;
static std::mutex s_mutex;
std::unique_lock<std::mutex> locked_guard(s_mutex);
guard.swap(locked_guard);
return *s_source_map;
}
ClangExternalASTSourceCommon *
ClangExternalASTSourceCommon::Lookup(clang::ExternalASTSource *source) {
std::unique_lock<std::mutex> guard;
ASTSourceMap &source_map = GetSourceMap(guard);
ASTSourceMap::iterator iter = source_map.find(source);
if (iter != source_map.end()) {
return iter->second;
} else {
return nullptr;
}
}
ClangExternalASTSourceCommon::ClangExternalASTSourceCommon()
: clang::ExternalASTSource() {
g_TotalSizeOfMetadata += m_metadata.size();
std::unique_lock<std::mutex> guard;
GetSourceMap(guard)[this] = this;
}
ClangExternalASTSourceCommon::~ClangExternalASTSourceCommon() {
std::unique_lock<std::mutex> guard;
GetSourceMap(guard).erase(this);
g_TotalSizeOfMetadata -= m_metadata.size();
}
ClangASTMetadata *
ClangExternalASTSourceCommon::GetMetadata(const void *object) {
if (HasMetadata(object))
return &m_metadata[object];
else
return nullptr;
}
void ClangExternalASTSourceCommon::SetMetadata(const void *object,
ClangASTMetadata &metadata) {
uint64_t orig_size = m_metadata.size();
m_metadata[object] = metadata;
uint64_t new_size = m_metadata.size();
g_TotalSizeOfMetadata += (new_size - orig_size);
}
bool ClangExternalASTSourceCommon::HasMetadata(const void *object) {
return m_metadata.find(object) != m_metadata.end();
}
void ClangASTMetadata::Dump(Stream *s) {
lldb::user_id_t uid = GetUserID();
if (uid != LLDB_INVALID_UID) {
s->Printf("uid=0x%" PRIx64, uid);
}
uint64_t isa_ptr = GetISAPtr();
if (isa_ptr != 0) {
s->Printf("isa_ptr=0x%" PRIx64, isa_ptr);
}
const char *obj_ptr_name = GetObjectPtrName();
if (obj_ptr_name) {
s->Printf("obj_ptr_name=\"%s\" ", obj_ptr_name);
}
if (m_is_dynamic_cxx) {
s->Printf("is_dynamic_cxx=%i ", m_is_dynamic_cxx);
}
s->EOL();
}

View File

@@ -0,0 +1,50 @@
//===-- ClangUtil.cpp -------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
// A collection of helper methods and data structures for manipulating clang
// types and decls.
//===----------------------------------------------------------------------===//
#include "lldb/Symbol/ClangUtil.h"
#include "lldb/Symbol/ClangASTContext.h"
using namespace clang;
using namespace lldb_private;
bool ClangUtil::IsClangType(const CompilerType &ct) {
if (llvm::dyn_cast_or_null<ClangASTContext>(ct.GetTypeSystem()) == nullptr)
return false;
if (!ct.GetOpaqueQualType())
return false;
return true;
}
QualType ClangUtil::GetQualType(const CompilerType &ct) {
// Make sure we have a clang type before making a clang::QualType
if (!IsClangType(ct))
return QualType();
return QualType::getFromOpaquePtr(ct.GetOpaqueQualType());
}
QualType ClangUtil::GetCanonicalQualType(const CompilerType &ct) {
if (!IsClangType(ct))
return QualType();
return GetQualType(ct).getCanonicalType();
}
CompilerType ClangUtil::RemoveFastQualifiers(const CompilerType &ct) {
if (!IsClangType(ct))
return ct;
QualType qual_type(GetQualType(ct));
qual_type.removeLocalFastQualifiers();
return CompilerType(ct.GetTypeSystem(), qual_type.getAsOpaquePtr());
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,434 @@
//===-- 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/Core/Module.h"
#include "lldb/Symbol/LineTable.h"
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Symbol/VariableList.h"
#include "lldb/Target/Language.h"
using namespace lldb;
using namespace lldb_private;
CompileUnit::CompileUnit(const lldb::ModuleSP &module_sp, void *user_data,
const char *pathname, const lldb::user_id_t cu_sym_id,
lldb::LanguageType language,
lldb_private::LazyBool is_optimized)
: ModuleChild(module_sp), FileSpec(pathname, false), UserID(cu_sym_id),
m_user_data(user_data), m_language(language), m_flags(0), m_functions(),
m_support_files(), m_line_table_ap(), m_variables(),
m_is_optimized(is_optimized) {
if (language != eLanguageTypeUnknown)
m_flags.Set(flagsParsedLanguage);
assert(module_sp);
}
CompileUnit::CompileUnit(const lldb::ModuleSP &module_sp, void *user_data,
const FileSpec &fspec, const lldb::user_id_t cu_sym_id,
lldb::LanguageType language,
lldb_private::LazyBool is_optimized)
: ModuleChild(module_sp), FileSpec(fspec), UserID(cu_sym_id),
m_user_data(user_data), m_language(language), m_flags(0), m_functions(),
m_support_files(), m_line_table_ap(), m_variables(),
m_is_optimized(is_optimized) {
if (language != eLanguageTypeUnknown)
m_flags.Set(flagsParsedLanguage);
assert(module_sp);
}
CompileUnit::~CompileUnit() {}
void CompileUnit::CalculateSymbolContext(SymbolContext *sc) {
sc->comp_unit = this;
GetModule()->CalculateSymbolContext(sc);
}
ModuleSP CompileUnit::CalculateSymbolContextModule() { return GetModule(); }
CompileUnit *CompileUnit::CalculateSymbolContextCompileUnit() { return this; }
void CompileUnit::DumpSymbolContext(Stream *s) {
GetModule()->DumpSymbolContext(s);
s->Printf(", CompileUnit{0x%8.8" PRIx64 "}", GetID());
}
void CompileUnit::GetDescription(Stream *s,
lldb::DescriptionLevel level) const {
const char *language = Language::GetNameForLanguageType(m_language);
*s << "id = " << (const UserID &)*this << ", file = \""
<< (const FileSpec &)*this << "\", language = \"" << language << '"';
}
//----------------------------------------------------------------------
// 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 {
const char *language = Language::GetNameForLanguageType(m_language);
s->Printf("%p: ", static_cast<const void *>(this));
s->Indent();
*s << "CompileUnit" << static_cast<const UserID &>(*this) << ", language = \""
<< language << "\", file = '" << static_cast<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 Mangled::Tokens token list. This
// function currently implements an interactive approach designed to find
// all instances of certain functions. It isn't designed to 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;
}
lldb::LanguageType CompileUnit::GetLanguage() {
if (m_language == eLanguageTypeUnknown) {
if (m_flags.IsClear(flagsParsedLanguage)) {
m_flags.Set(flagsParsedLanguage);
SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor();
if (symbol_vendor) {
SymbolContext sc;
CalculateSymbolContext(&sc);
m_language = symbol_vendor->ParseCompileUnitLanguage(sc);
}
}
}
return m_language;
}
LineTable *CompileUnit::GetLineTable() {
if (m_line_table_ap.get() == nullptr) {
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 == nullptr)
m_flags.Clear(flagsParsedLineTable);
else
m_flags.Set(flagsParsedLineTable);
m_line_table_ap.reset(line_table);
}
DebugMacros *CompileUnit::GetDebugMacros() {
if (m_debug_macros_sp.get() == nullptr) {
if (m_flags.IsClear(flagsParsedDebugMacros)) {
m_flags.Set(flagsParsedDebugMacros);
SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor();
if (symbol_vendor) {
SymbolContext sc;
CalculateSymbolContext(&sc);
symbol_vendor->ParseCompileUnitDebugMacros(sc);
}
}
}
return m_debug_macros_sp.get();
}
void CompileUnit::SetDebugMacros(const DebugMacrosSP &debug_macros_sp) {
if (debug_macros_sp.get() == nullptr)
m_flags.Clear(flagsParsedDebugMacros);
else
m_flags.Set(flagsParsedDebugMacros);
m_debug_macros_sp = debug_macros_sp;
}
VariableListSP CompileUnit::GetVariableList(bool can_create) {
if (m_variables.get() == nullptr && 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, bool exact,
LineEntry *line_entry_ptr) {
uint32_t file_idx = 0;
if (file_spec_ptr) {
file_idx = GetSupportFiles().FindFileIndex(1, *file_spec_ptr, true);
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 artificially added.)
// So prefer the one further on in the support files if it exists...
FileSpecList &support_files = GetSupportFiles();
const bool full = true;
file_idx = support_files.FindFileIndex(
1, support_files.GetFileSpecAtIndex(0), full);
if (file_idx == UINT32_MAX)
file_idx = 0;
}
LineTable *line_table = GetLineTable();
if (line_table)
return line_table->FindLineEntryIndexByFileIndex(start_idx, file_idx, line,
exact, 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) {
// First find all of the file indexes that match our "file_spec". If
// "file_spec" has an empty directory, then only compare the basenames
// when finding file indexes
std::vector<uint32_t> file_indexes;
const bool full_match = (bool)file_spec.GetDirectory();
const bool remove_backup_dots = true;
bool file_spec_matches_cu_file_spec =
FileSpec::Equal(file_spec, *this, full_match, remove_backup_dots);
// If we are not looking for inlined functions and our file spec doesn't
// match then we are done...
if (file_spec_matches_cu_file_spec == false && check_inlines == false)
return 0;
uint32_t file_idx =
GetSupportFiles().FindFileIndex(1, file_spec, true, remove_backup_dots);
while (file_idx != UINT32_MAX) {
file_indexes.push_back(file_idx);
file_idx = GetSupportFiles().FindFileIndex(file_idx + 1, file_spec, true,
remove_backup_dots);
}
const size_t num_file_indexes = file_indexes.size();
if (num_file_indexes == 0)
return 0;
const uint32_t prev_size = sc_list.GetSize();
SymbolContext sc(GetModule());
sc.comp_unit = this;
if (line != 0) {
LineTable *line_table = sc.comp_unit->GetLineTable();
if (line_table != nullptr) {
uint32_t found_line;
uint32_t line_idx;
if (num_file_indexes == 1) {
// We only have a single support file that matches, so use
// the line table function that searches for a line entries
// that match a single support file index
LineEntry line_entry;
line_idx = line_table->FindLineEntryIndexByFileIndex(
0, file_indexes.front(), line, exact, &line_entry);
// If "exact == true", then "found_line" will be the same
// as "line". If "exact == false", the "found_line" will be the
// closest line entry with a line number greater than "line" and
// we will use this for our subsequent line exact matches below.
found_line = line_entry.line;
while (line_idx != UINT32_MAX) {
// If they only asked for the line entry, then we're done, we can just
// copy that over.
// But if they wanted more than just the line number, fill it in.
if (resolve_scope == eSymbolContextLineEntry) {
sc.line_entry = line_entry;
} else {
line_entry.range.GetBaseAddress().CalculateSymbolContext(
&sc, resolve_scope);
}
sc_list.Append(sc);
line_idx = line_table->FindLineEntryIndexByFileIndex(
line_idx + 1, file_indexes.front(), found_line, true,
&line_entry);
}
} else {
// We found multiple support files that match "file_spec" so use
// the line table function that searches for a line entries
// that match a multiple support file indexes.
LineEntry line_entry;
line_idx = line_table->FindLineEntryIndexByFileIndex(
0, file_indexes, line, exact, &line_entry);
// If "exact == true", then "found_line" will be the same
// as "line". If "exact == false", the "found_line" will be the
// closest line entry with a line number greater than "line" and
// we will use this for our subsequent line exact matches below.
found_line = line_entry.line;
while (line_idx != UINT32_MAX) {
if (resolve_scope == eSymbolContextLineEntry) {
sc.line_entry = line_entry;
} else {
line_entry.range.GetBaseAddress().CalculateSymbolContext(
&sc, resolve_scope);
}
sc_list.Append(sc);
line_idx = line_table->FindLineEntryIndexByFileIndex(
line_idx + 1, file_indexes, found_line, true, &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;
}
bool CompileUnit::GetIsOptimized() {
if (m_is_optimized == eLazyBoolCalculate) {
m_is_optimized = eLazyBoolNo;
if (SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor()) {
SymbolContext sc;
CalculateSymbolContext(&sc);
if (symbol_vendor->ParseCompileUnitIsOptimized(sc))
m_is_optimized = eLazyBoolYes;
}
}
return m_is_optimized;
}
void CompileUnit::SetVariableList(VariableListSP &variables) {
m_variables = variables;
}
const std::vector<ConstString> &CompileUnit::GetImportedModules() {
if (m_imported_modules.empty() &&
m_flags.IsClear(flagsParsedImportedModules)) {
m_flags.Set(flagsParsedImportedModules);
if (SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor()) {
SymbolContext sc;
CalculateSymbolContext(&sc);
symbol_vendor->ParseImportedModules(sc, m_imported_modules);
}
}
return m_imported_modules;
}
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; }

View File

@@ -0,0 +1,54 @@
//===-- CompilerDecl.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/CompilerDecl.h"
#include "lldb/Symbol/CompilerDeclContext.h"
#include "lldb/Symbol/TypeSystem.h"
using namespace lldb_private;
bool CompilerDecl::IsClang() const {
return IsValid() && m_type_system->getKind() == TypeSystem::eKindClang;
}
ConstString CompilerDecl::GetName() const {
return m_type_system->DeclGetName(m_opaque_decl);
}
ConstString CompilerDecl::GetMangledName() const {
return m_type_system->DeclGetMangledName(m_opaque_decl);
}
CompilerDeclContext CompilerDecl::GetDeclContext() const {
return m_type_system->DeclGetDeclContext(m_opaque_decl);
}
CompilerType CompilerDecl::GetFunctionReturnType() const {
return m_type_system->DeclGetFunctionReturnType(m_opaque_decl);
}
size_t CompilerDecl::GetNumFunctionArguments() const {
return m_type_system->DeclGetFunctionNumArguments(m_opaque_decl);
}
CompilerType CompilerDecl::GetFunctionArgumentType(size_t arg_idx) const {
return m_type_system->DeclGetFunctionArgumentType(m_opaque_decl, arg_idx);
}
bool lldb_private::operator==(const lldb_private::CompilerDecl &lhs,
const lldb_private::CompilerDecl &rhs) {
return lhs.GetTypeSystem() == rhs.GetTypeSystem() &&
lhs.GetOpaqueDecl() == rhs.GetOpaqueDecl();
}
bool lldb_private::operator!=(const lldb_private::CompilerDecl &lhs,
const lldb_private::CompilerDecl &rhs) {
return lhs.GetTypeSystem() != rhs.GetTypeSystem() ||
lhs.GetOpaqueDecl() != rhs.GetOpaqueDecl();
}

View File

@@ -0,0 +1,73 @@
//===-- CompilerDeclContext.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/CompilerDeclContext.h"
#include "lldb/Symbol/CompilerDecl.h"
#include "lldb/Symbol/TypeSystem.h"
#include <vector>
using namespace lldb_private;
std::vector<CompilerDecl>
CompilerDeclContext::FindDeclByName(ConstString name,
const bool ignore_using_decls) {
if (IsValid())
return m_type_system->DeclContextFindDeclByName(m_opaque_decl_ctx, name,
ignore_using_decls);
else
return std::vector<CompilerDecl>();
}
bool CompilerDeclContext::IsClang() const {
return IsValid() && m_type_system->getKind() == TypeSystem::eKindClang;
}
ConstString CompilerDeclContext::GetName() const {
if (IsValid())
return m_type_system->DeclContextGetName(m_opaque_decl_ctx);
else
return ConstString();
}
ConstString CompilerDeclContext::GetScopeQualifiedName() const {
if (IsValid())
return m_type_system->DeclContextGetScopeQualifiedName(m_opaque_decl_ctx);
else
return ConstString();
}
bool CompilerDeclContext::IsStructUnionOrClass() const {
if (IsValid())
return m_type_system->DeclContextIsStructUnionOrClass(m_opaque_decl_ctx);
else
return false;
}
bool CompilerDeclContext::IsClassMethod(lldb::LanguageType *language_ptr,
bool *is_instance_method_ptr,
ConstString *language_object_name_ptr) {
if (IsValid())
return m_type_system->DeclContextIsClassMethod(
m_opaque_decl_ctx, language_ptr, is_instance_method_ptr,
language_object_name_ptr);
else
return false;
}
bool lldb_private::operator==(const lldb_private::CompilerDeclContext &lhs,
const lldb_private::CompilerDeclContext &rhs) {
return lhs.GetTypeSystem() == rhs.GetTypeSystem() &&
lhs.GetOpaqueDeclContext() == rhs.GetOpaqueDeclContext();
}
bool lldb_private::operator!=(const lldb_private::CompilerDeclContext &lhs,
const lldb_private::CompilerDeclContext &rhs) {
return lhs.GetTypeSystem() != rhs.GetTypeSystem() ||
lhs.GetOpaqueDeclContext() != rhs.GetOpaqueDeclContext();
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,54 @@
//===-- DebugMacros.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/DebugMacros.h"
#include "lldb/Symbol/CompileUnit.h"
using namespace lldb_private;
DebugMacroEntry::DebugMacroEntry(EntryType type, uint32_t line,
uint32_t debug_line_file_idx, const char *str)
: m_type(type), m_line(line), m_debug_line_file_idx(debug_line_file_idx),
m_str(str) {}
DebugMacroEntry::DebugMacroEntry(EntryType type,
const DebugMacrosSP &debug_macros_sp)
: m_type(type), m_line(0), m_debug_line_file_idx(0),
m_debug_macros_sp(debug_macros_sp) {}
const FileSpec &DebugMacroEntry::GetFileSpec(CompileUnit *comp_unit) const {
return comp_unit->GetSupportFiles().GetFileSpecAtIndex(m_debug_line_file_idx);
}
DebugMacroEntry DebugMacroEntry::CreateDefineEntry(uint32_t line,
const char *str) {
return DebugMacroEntry(DebugMacroEntry::DEFINE, line, 0, str);
}
DebugMacroEntry DebugMacroEntry::CreateUndefEntry(uint32_t line,
const char *str) {
return DebugMacroEntry(DebugMacroEntry::UNDEF, line, 0, str);
}
DebugMacroEntry
DebugMacroEntry::CreateStartFileEntry(uint32_t line,
uint32_t debug_line_file_idx) {
return DebugMacroEntry(DebugMacroEntry::START_FILE, line, debug_line_file_idx,
nullptr);
}
DebugMacroEntry DebugMacroEntry::CreateEndFileEntry() {
return DebugMacroEntry(DebugMacroEntry::END_FILE, 0, 0, nullptr);
}
DebugMacroEntry
DebugMacroEntry::CreateIndirectEntry(const DebugMacrosSP &debug_macros_sp) {
return DebugMacroEntry(DebugMacroEntry::INDIRECT, debug_macros_sp);
}

View File

@@ -0,0 +1,97 @@
//===-- 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/Utility/Stream.h"
using namespace lldb_private;
void Declaration::Dump(Stream *s, bool show_fullpaths) const {
if (m_file) {
*s << ", decl = ";
if (show_fullpaths)
*s << m_file;
else
*s << m_file.GetFilename();
if (m_line > 0)
s->Printf(":%u", m_line);
#ifdef LLDB_ENABLE_DECLARATION_COLUMNS
if (m_column > 0)
s->Printf(":%u", m_column);
#endif
} else {
if (m_line > 0) {
s->Printf(", line = %u", m_line);
#ifdef LLDB_ENABLE_DECLARATION_COLUMNS
if (m_column > 0)
s->Printf(":%u", m_column);
#endif
}
#ifdef LLDB_ENABLE_DECLARATION_COLUMNS
else if (m_column > 0)
s->Printf(", column = %u", m_column);
#endif
}
}
bool Declaration::DumpStopContext(Stream *s, bool show_fullpaths) const {
if (m_file) {
if (show_fullpaths)
*s << m_file;
else
m_file.GetFilename().Dump(s);
if (m_line > 0)
s->Printf(":%u", m_line);
#ifdef LLDB_ENABLE_DECLARATION_COLUMNS
if (m_column > 0)
s->Printf(":%u", m_column);
#endif
return true;
} else if (m_line > 0) {
s->Printf(" line %u", m_line);
#ifdef LLDB_ENABLE_DECLARATION_COLUMNS
if (m_column > 0)
s->Printf(":%u", m_column);
#endif
return true;
}
return false;
}
size_t Declaration::MemorySize() const { return sizeof(Declaration); }
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;
#ifdef LLDB_ENABLE_DECLARATION_COLUMNS
if (a.m_column < b.m_column)
return -1;
else if (a.m_column > b.m_column)
return 1;
#endif
return 0;
}
bool lldb_private::operator==(const Declaration &lhs, const Declaration &rhs) {
#ifdef LLDB_ENABLE_DECLARATION_COLUMNS
if (lhs.GetColumn() == rhs.GetColumn())
if (lhs.GetLine() == rhs.GetLine())
return lhs.GetFile() == rhs.GetFile();
#else
if (lhs.GetLine() == rhs.GetLine())
return FileSpec::Equal(lhs.GetFile(), rhs.GetFile(), true, true);
#endif
return false;
}

View File

@@ -0,0 +1,482 @@
//===-- FuncUnwinders.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/FuncUnwinders.h"
#include "lldb/Core/Address.h"
#include "lldb/Core/AddressRange.h"
#include "lldb/Symbol/ArmUnwindInfo.h"
#include "lldb/Symbol/CompactUnwindInfo.h"
#include "lldb/Symbol/DWARFCallFrameInfo.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Symbol/UnwindTable.h"
#include "lldb/Target/ABI.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterNumber.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/UnwindAssembly.h"
using namespace lldb;
using namespace lldb_private;
//------------------------------------------------
/// constructor
//------------------------------------------------
FuncUnwinders::FuncUnwinders(UnwindTable &unwind_table, AddressRange range)
: m_unwind_table(unwind_table), m_range(range), m_mutex(),
m_unwind_plan_assembly_sp(), m_unwind_plan_eh_frame_sp(),
m_unwind_plan_eh_frame_augmented_sp(), m_unwind_plan_compact_unwind(),
m_unwind_plan_arm_unwind_sp(), m_unwind_plan_fast_sp(),
m_unwind_plan_arch_default_sp(),
m_unwind_plan_arch_default_at_func_entry_sp(),
m_tried_unwind_plan_assembly(false), m_tried_unwind_plan_eh_frame(false),
m_tried_unwind_plan_debug_frame(false),
m_tried_unwind_plan_eh_frame_augmented(false),
m_tried_unwind_plan_debug_frame_augmented(false),
m_tried_unwind_plan_compact_unwind(false),
m_tried_unwind_plan_arm_unwind(false), m_tried_unwind_fast(false),
m_tried_unwind_arch_default(false),
m_tried_unwind_arch_default_at_func_entry(false),
m_first_non_prologue_insn() {}
//------------------------------------------------
/// destructor
//------------------------------------------------
FuncUnwinders::~FuncUnwinders() {}
UnwindPlanSP FuncUnwinders::GetUnwindPlanAtCallSite(Target &target,
int current_offset) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (UnwindPlanSP plan_sp = GetEHFrameUnwindPlan(target, current_offset))
return plan_sp;
if (UnwindPlanSP plan_sp = GetDebugFrameUnwindPlan(target, current_offset))
return plan_sp;
if (UnwindPlanSP plan_sp = GetCompactUnwindUnwindPlan(target, current_offset))
return plan_sp;
if (UnwindPlanSP plan_sp = GetArmUnwindUnwindPlan(target, current_offset))
return plan_sp;
return nullptr;
}
UnwindPlanSP FuncUnwinders::GetCompactUnwindUnwindPlan(Target &target,
int current_offset) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (m_unwind_plan_compact_unwind.size() > 0)
return m_unwind_plan_compact_unwind[0]; // FIXME support multiple compact
// unwind plans for one func
if (m_tried_unwind_plan_compact_unwind)
return UnwindPlanSP();
m_tried_unwind_plan_compact_unwind = true;
if (m_range.GetBaseAddress().IsValid()) {
Address current_pc(m_range.GetBaseAddress());
if (current_offset != -1)
current_pc.SetOffset(current_pc.GetOffset() + current_offset);
CompactUnwindInfo *compact_unwind = m_unwind_table.GetCompactUnwindInfo();
if (compact_unwind) {
UnwindPlanSP unwind_plan_sp(new UnwindPlan(lldb::eRegisterKindGeneric));
if (compact_unwind->GetUnwindPlan(target, current_pc, *unwind_plan_sp)) {
m_unwind_plan_compact_unwind.push_back(unwind_plan_sp);
return m_unwind_plan_compact_unwind[0]; // FIXME support multiple
// compact unwind plans for one
// func
}
}
}
return UnwindPlanSP();
}
UnwindPlanSP FuncUnwinders::GetEHFrameUnwindPlan(Target &target,
int current_offset) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (m_unwind_plan_eh_frame_sp.get() || m_tried_unwind_plan_eh_frame)
return m_unwind_plan_eh_frame_sp;
m_tried_unwind_plan_eh_frame = true;
if (m_range.GetBaseAddress().IsValid()) {
Address current_pc(m_range.GetBaseAddress());
if (current_offset != -1)
current_pc.SetOffset(current_pc.GetOffset() + current_offset);
DWARFCallFrameInfo *eh_frame = m_unwind_table.GetEHFrameInfo();
if (eh_frame) {
m_unwind_plan_eh_frame_sp.reset(
new UnwindPlan(lldb::eRegisterKindGeneric));
if (!eh_frame->GetUnwindPlan(current_pc, *m_unwind_plan_eh_frame_sp))
m_unwind_plan_eh_frame_sp.reset();
}
}
return m_unwind_plan_eh_frame_sp;
}
UnwindPlanSP FuncUnwinders::GetDebugFrameUnwindPlan(Target &target,
int current_offset) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (m_unwind_plan_debug_frame_sp || m_tried_unwind_plan_debug_frame)
return m_unwind_plan_debug_frame_sp;
m_tried_unwind_plan_debug_frame = true;
if (m_range.GetBaseAddress().IsValid()) {
Address current_pc(m_range.GetBaseAddress());
if (current_offset != -1)
current_pc.SetOffset(current_pc.GetOffset() + current_offset);
DWARFCallFrameInfo *debug_frame = m_unwind_table.GetDebugFrameInfo();
if (debug_frame) {
m_unwind_plan_debug_frame_sp.reset(
new UnwindPlan(lldb::eRegisterKindGeneric));
if (!debug_frame->GetUnwindPlan(current_pc,
*m_unwind_plan_debug_frame_sp))
m_unwind_plan_debug_frame_sp.reset();
}
}
return m_unwind_plan_debug_frame_sp;
}
UnwindPlanSP FuncUnwinders::GetArmUnwindUnwindPlan(Target &target,
int current_offset) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (m_unwind_plan_arm_unwind_sp.get() || m_tried_unwind_plan_arm_unwind)
return m_unwind_plan_arm_unwind_sp;
m_tried_unwind_plan_arm_unwind = true;
if (m_range.GetBaseAddress().IsValid()) {
Address current_pc(m_range.GetBaseAddress());
if (current_offset != -1)
current_pc.SetOffset(current_pc.GetOffset() + current_offset);
ArmUnwindInfo *arm_unwind_info = m_unwind_table.GetArmUnwindInfo();
if (arm_unwind_info) {
m_unwind_plan_arm_unwind_sp.reset(
new UnwindPlan(lldb::eRegisterKindGeneric));
if (!arm_unwind_info->GetUnwindPlan(target, current_pc,
*m_unwind_plan_arm_unwind_sp))
m_unwind_plan_arm_unwind_sp.reset();
}
}
return m_unwind_plan_arm_unwind_sp;
}
UnwindPlanSP FuncUnwinders::GetEHFrameAugmentedUnwindPlan(Target &target,
Thread &thread,
int current_offset) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (m_unwind_plan_eh_frame_augmented_sp.get() ||
m_tried_unwind_plan_eh_frame_augmented)
return m_unwind_plan_eh_frame_augmented_sp;
// Only supported on x86 architectures where we get eh_frame from the compiler
// that describes
// the prologue instructions perfectly, and sometimes the epilogue
// instructions too.
if (target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_32_i386 &&
target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64 &&
target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h) {
m_tried_unwind_plan_eh_frame_augmented = true;
return m_unwind_plan_eh_frame_augmented_sp;
}
m_tried_unwind_plan_eh_frame_augmented = true;
UnwindPlanSP eh_frame_plan = GetEHFrameUnwindPlan(target, current_offset);
if (!eh_frame_plan)
return m_unwind_plan_eh_frame_augmented_sp;
m_unwind_plan_eh_frame_augmented_sp.reset(new UnwindPlan(*eh_frame_plan));
// Augment the eh_frame instructions with epilogue descriptions if necessary
// so the
// UnwindPlan can be used at any instruction in the function.
UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
if (assembly_profiler_sp) {
if (!assembly_profiler_sp->AugmentUnwindPlanFromCallSite(
m_range, thread, *m_unwind_plan_eh_frame_augmented_sp)) {
m_unwind_plan_eh_frame_augmented_sp.reset();
}
} else {
m_unwind_plan_eh_frame_augmented_sp.reset();
}
return m_unwind_plan_eh_frame_augmented_sp;
}
UnwindPlanSP
FuncUnwinders::GetDebugFrameAugmentedUnwindPlan(Target &target, Thread &thread,
int current_offset) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (m_unwind_plan_debug_frame_augmented_sp.get() ||
m_tried_unwind_plan_debug_frame_augmented)
return m_unwind_plan_debug_frame_augmented_sp;
// Only supported on x86 architectures where we get debug_frame from the
// compiler that describes the prologue instructions perfectly, and sometimes
// the epilogue instructions too.
if (target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_32_i386 &&
target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64 &&
target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h) {
m_tried_unwind_plan_debug_frame_augmented = true;
return m_unwind_plan_debug_frame_augmented_sp;
}
m_tried_unwind_plan_debug_frame_augmented = true;
UnwindPlanSP debug_frame_plan =
GetDebugFrameUnwindPlan(target, current_offset);
if (!debug_frame_plan)
return m_unwind_plan_debug_frame_augmented_sp;
m_unwind_plan_debug_frame_augmented_sp.reset(
new UnwindPlan(*debug_frame_plan));
// Augment the debug_frame instructions with epilogue descriptions if
// necessary so the UnwindPlan can be used at any instruction in the function.
UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
if (assembly_profiler_sp) {
if (!assembly_profiler_sp->AugmentUnwindPlanFromCallSite(
m_range, thread, *m_unwind_plan_debug_frame_augmented_sp)) {
m_unwind_plan_debug_frame_augmented_sp.reset();
}
} else
m_unwind_plan_debug_frame_augmented_sp.reset();
return m_unwind_plan_debug_frame_augmented_sp;
}
UnwindPlanSP FuncUnwinders::GetAssemblyUnwindPlan(Target &target,
Thread &thread,
int current_offset) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (m_unwind_plan_assembly_sp.get() || m_tried_unwind_plan_assembly ||
m_unwind_table.GetAllowAssemblyEmulationUnwindPlans() == false) {
return m_unwind_plan_assembly_sp;
}
m_tried_unwind_plan_assembly = true;
UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
if (assembly_profiler_sp) {
m_unwind_plan_assembly_sp.reset(new UnwindPlan(lldb::eRegisterKindGeneric));
if (!assembly_profiler_sp->GetNonCallSiteUnwindPlanFromAssembly(
m_range, thread, *m_unwind_plan_assembly_sp)) {
m_unwind_plan_assembly_sp.reset();
}
}
return m_unwind_plan_assembly_sp;
}
// This method compares the pc unwind rule in the first row of two UnwindPlans.
// If they have the same way of getting the pc value (e.g. "CFA - 8" + "CFA is
// sp"),
// then it will return LazyBoolTrue.
LazyBool FuncUnwinders::CompareUnwindPlansForIdenticalInitialPCLocation(
Thread &thread, const UnwindPlanSP &a, const UnwindPlanSP &b) {
LazyBool plans_are_identical = eLazyBoolCalculate;
RegisterNumber pc_reg(thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
uint32_t pc_reg_lldb_regnum = pc_reg.GetAsKind(eRegisterKindLLDB);
if (a.get() && b.get()) {
UnwindPlan::RowSP a_first_row = a->GetRowAtIndex(0);
UnwindPlan::RowSP b_first_row = b->GetRowAtIndex(0);
if (a_first_row.get() && b_first_row.get()) {
UnwindPlan::Row::RegisterLocation a_pc_regloc;
UnwindPlan::Row::RegisterLocation b_pc_regloc;
a_first_row->GetRegisterInfo(pc_reg_lldb_regnum, a_pc_regloc);
b_first_row->GetRegisterInfo(pc_reg_lldb_regnum, b_pc_regloc);
plans_are_identical = eLazyBoolYes;
if (a_first_row->GetCFAValue() != b_first_row->GetCFAValue()) {
plans_are_identical = eLazyBoolNo;
}
if (a_pc_regloc != b_pc_regloc) {
plans_are_identical = eLazyBoolNo;
}
}
}
return plans_are_identical;
}
UnwindPlanSP FuncUnwinders::GetUnwindPlanAtNonCallSite(Target &target,
Thread &thread,
int current_offset) {
UnwindPlanSP eh_frame_sp = GetEHFrameUnwindPlan(target, current_offset);
if (!eh_frame_sp)
eh_frame_sp = GetDebugFrameUnwindPlan(target, current_offset);
UnwindPlanSP arch_default_at_entry_sp =
GetUnwindPlanArchitectureDefaultAtFunctionEntry(thread);
UnwindPlanSP arch_default_sp = GetUnwindPlanArchitectureDefault(thread);
UnwindPlanSP assembly_sp =
GetAssemblyUnwindPlan(target, thread, current_offset);
// This point of this code is to detect when a function is using a
// non-standard ABI, and the eh_frame correctly describes that alternate ABI.
// This is addressing a specific situation on x86_64 linux systems where one
// function in a library pushes a value on the stack and jumps to another
// function. So using an assembly instruction based unwind will not work when
// you're in the second function - the stack has been modified in a non-ABI
// way. But we have eh_frame that correctly describes how to unwind from this
// location. So we're looking to see if the initial pc register save location
// from the eh_frame is different from the assembly unwind, the arch default
// unwind, and the arch default at initial function entry.
//
// We may have eh_frame that describes the entire function -- or we may have
// eh_frame that only describes the unwind after the prologue has executed --
// so we need to check both the arch default (once the prologue has executed)
// and the arch default at initial function entry. And we may be running on a
// target where we have only some of the assembly/arch default unwind plans
// available.
if (CompareUnwindPlansForIdenticalInitialPCLocation(
thread, eh_frame_sp, arch_default_at_entry_sp) == eLazyBoolNo &&
CompareUnwindPlansForIdenticalInitialPCLocation(
thread, eh_frame_sp, arch_default_sp) == eLazyBoolNo &&
CompareUnwindPlansForIdenticalInitialPCLocation(
thread, assembly_sp, arch_default_sp) == eLazyBoolNo) {
return eh_frame_sp;
}
if (UnwindPlanSP plan_sp =
GetEHFrameAugmentedUnwindPlan(target, thread, current_offset))
return plan_sp;
if (UnwindPlanSP plan_sp =
GetDebugFrameAugmentedUnwindPlan(target, thread, current_offset))
return plan_sp;
return assembly_sp;
}
UnwindPlanSP FuncUnwinders::GetUnwindPlanFastUnwind(Target &target,
Thread &thread) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (m_unwind_plan_fast_sp.get() || m_tried_unwind_fast)
return m_unwind_plan_fast_sp;
m_tried_unwind_fast = true;
UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
if (assembly_profiler_sp) {
m_unwind_plan_fast_sp.reset(new UnwindPlan(lldb::eRegisterKindGeneric));
if (!assembly_profiler_sp->GetFastUnwindPlan(m_range, thread,
*m_unwind_plan_fast_sp)) {
m_unwind_plan_fast_sp.reset();
}
}
return m_unwind_plan_fast_sp;
}
UnwindPlanSP FuncUnwinders::GetUnwindPlanArchitectureDefault(Thread &thread) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (m_unwind_plan_arch_default_sp.get() || m_tried_unwind_arch_default)
return m_unwind_plan_arch_default_sp;
m_tried_unwind_arch_default = true;
Address current_pc;
ProcessSP process_sp(thread.CalculateProcess());
if (process_sp) {
ABI *abi = process_sp->GetABI().get();
if (abi) {
m_unwind_plan_arch_default_sp.reset(
new UnwindPlan(lldb::eRegisterKindGeneric));
if (!abi->CreateDefaultUnwindPlan(*m_unwind_plan_arch_default_sp)) {
m_unwind_plan_arch_default_sp.reset();
}
}
}
return m_unwind_plan_arch_default_sp;
}
UnwindPlanSP
FuncUnwinders::GetUnwindPlanArchitectureDefaultAtFunctionEntry(Thread &thread) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (m_unwind_plan_arch_default_at_func_entry_sp.get() ||
m_tried_unwind_arch_default_at_func_entry)
return m_unwind_plan_arch_default_at_func_entry_sp;
m_tried_unwind_arch_default_at_func_entry = true;
Address current_pc;
ProcessSP process_sp(thread.CalculateProcess());
if (process_sp) {
ABI *abi = process_sp->GetABI().get();
if (abi) {
m_unwind_plan_arch_default_at_func_entry_sp.reset(
new UnwindPlan(lldb::eRegisterKindGeneric));
if (!abi->CreateFunctionEntryUnwindPlan(
*m_unwind_plan_arch_default_at_func_entry_sp)) {
m_unwind_plan_arch_default_at_func_entry_sp.reset();
}
}
}
return m_unwind_plan_arch_default_at_func_entry_sp;
}
Address &FuncUnwinders::GetFirstNonPrologueInsn(Target &target) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (m_first_non_prologue_insn.IsValid())
return m_first_non_prologue_insn;
ExecutionContext exe_ctx(target.shared_from_this(), false);
UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
if (assembly_profiler_sp)
assembly_profiler_sp->FirstNonPrologueInsn(m_range, exe_ctx,
m_first_non_prologue_insn);
return m_first_non_prologue_insn;
}
const Address &FuncUnwinders::GetFunctionStartAddress() const {
return m_range.GetBaseAddress();
}
lldb::UnwindAssemblySP
FuncUnwinders::GetUnwindAssemblyProfiler(Target &target) {
UnwindAssemblySP assembly_profiler_sp;
ArchSpec arch;
if (m_unwind_table.GetArchitecture(arch)) {
arch.MergeFrom(target.GetArchitecture());
assembly_profiler_sp = UnwindAssembly::FindPlugin(arch);
}
return assembly_profiler_sp;
}
Address FuncUnwinders::GetLSDAAddress(Target &target) {
Address lsda_addr;
UnwindPlanSP unwind_plan_sp = GetEHFrameUnwindPlan(target, -1);
if (unwind_plan_sp.get() == nullptr) {
unwind_plan_sp = GetCompactUnwindUnwindPlan(target, -1);
}
if (unwind_plan_sp.get() && unwind_plan_sp->GetLSDAAddress().IsValid()) {
lsda_addr = unwind_plan_sp->GetLSDAAddress();
}
return lsda_addr;
}
Address FuncUnwinders::GetPersonalityRoutinePtrAddress(Target &target) {
Address personality_addr;
UnwindPlanSP unwind_plan_sp = GetEHFrameUnwindPlan(target, -1);
if (unwind_plan_sp.get() == nullptr) {
unwind_plan_sp = GetCompactUnwindUnwindPlan(target, -1);
}
if (unwind_plan_sp.get() &&
unwind_plan_sp->GetPersonalityFunctionPtr().IsValid()) {
personality_addr = unwind_plan_sp->GetPersonalityFunctionPtr();
}
return personality_addr;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More