[Lldb-commits] [lldb] r306397 - Add debug_frame section support
Pavel Labath via lldb-commits
lldb-commits at lists.llvm.org
Tue Jun 27 04:16:27 PDT 2017
Author: labath
Date: Tue Jun 27 04:16:26 2017
New Revision: 306397
URL: http://llvm.org/viewvc/llvm-project?rev=306397&view=rev
Log:
Add debug_frame section support
Summary:
This is a beefed-up version of D33504, which adds support for dwarf 4
debug_frame section format.
The main difference here is that the decision whether to use eh_frame or
debug_frame is done on a per-function basis instead of per-object file.
This is necessary because one module can contain both sections (for
example, the start files added by the linker will typically pull in
eh_frame), but we want to be able to access both, for maximum
information.
I also add unit test for parsing various CFI formats (eh_frame,
debug_frame v3 and debug_frame v4).
Reviewers: jasonmolenda, clayborg
Subscribers: mgorny, aprantl, abidh, lldb-commits, tatyana-krasnukha
Differential Revision: https://reviews.llvm.org/D34613
Added:
lldb/trunk/unittests/Symbol/Inputs/
lldb/trunk/unittests/Symbol/Inputs/basic-call-frame-info.yaml
lldb/trunk/unittests/Symbol/TestDWARFCallFrameInfo.cpp
Modified:
lldb/trunk/include/lldb/Symbol/DWARFCallFrameInfo.h
lldb/trunk/include/lldb/Symbol/FuncUnwinders.h
lldb/trunk/include/lldb/Symbol/UnwindTable.h
lldb/trunk/source/Commands/CommandObjectTarget.cpp
lldb/trunk/source/Symbol/DWARFCallFrameInfo.cpp
lldb/trunk/source/Symbol/FuncUnwinders.cpp
lldb/trunk/source/Symbol/UnwindTable.cpp
lldb/trunk/unittests/Symbol/CMakeLists.txt
Modified: lldb/trunk/include/lldb/Symbol/DWARFCallFrameInfo.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/DWARFCallFrameInfo.h?rev=306397&r1=306396&r2=306397&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Symbol/DWARFCallFrameInfo.h (original)
+++ lldb/trunk/include/lldb/Symbol/DWARFCallFrameInfo.h Tue Jun 27 04:16:26 2017
@@ -37,7 +37,7 @@ public:
DWARFCallFrameInfo(ObjectFile &objfile, lldb::SectionSP §ion,
lldb::RegisterKind reg_kind, bool is_eh_frame);
- ~DWARFCallFrameInfo();
+ ~DWARFCallFrameInfo() = default;
// Locate an AddressRange that includes the provided Address in this
// object's eh_frame/debug_info
@@ -74,12 +74,20 @@ public:
private:
enum { CFI_AUG_MAX_SIZE = 8, CFI_HEADER_SIZE = 8 };
+ enum CFIVersion {
+ CFI_VERSION1 = 1, // DWARF v.2
+ CFI_VERSION3 = 3, // DWARF v.3
+ CFI_VERSION4 = 4 // DWARF v.4, v.5
+ };
struct CIE {
dw_offset_t cie_offset;
uint8_t version;
char augmentation[CFI_AUG_MAX_SIZE]; // This is typically empty or very
// short.
+ uint8_t address_size = sizeof(uint32_t); // The size of a target address.
+ uint8_t segment_size = 0; // The size of a segment selector.
+
uint32_t code_align;
int32_t data_align;
uint32_t return_addr_reg_num;
Modified: lldb/trunk/include/lldb/Symbol/FuncUnwinders.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/FuncUnwinders.h?rev=306397&r1=306396&r2=306397&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Symbol/FuncUnwinders.h (original)
+++ lldb/trunk/include/lldb/Symbol/FuncUnwinders.h Tue Jun 27 04:16:26 2017
@@ -99,6 +99,13 @@ public:
Thread &thread,
int current_offset);
+ lldb::UnwindPlanSP GetDebugFrameUnwindPlan(Target &target,
+ int current_offset);
+
+ lldb::UnwindPlanSP GetDebugFrameAugmentedUnwindPlan(Target &target,
+ Thread &thread,
+ int current_offset);
+
lldb::UnwindPlanSP GetCompactUnwindUnwindPlan(Target &target,
int current_offset);
@@ -126,10 +133,12 @@ private:
lldb::UnwindPlanSP m_unwind_plan_assembly_sp;
lldb::UnwindPlanSP m_unwind_plan_eh_frame_sp;
- lldb::UnwindPlanSP m_unwind_plan_eh_frame_augmented_sp; // augmented by
- // assembly inspection
- // so it's valid
- // everywhere
+ lldb::UnwindPlanSP m_unwind_plan_debug_frame_sp;
+
+ // augmented by assembly inspection so it's valid everywhere
+ lldb::UnwindPlanSP m_unwind_plan_eh_frame_augmented_sp;
+ lldb::UnwindPlanSP m_unwind_plan_debug_frame_augmented_sp;
+
std::vector<lldb::UnwindPlanSP> m_unwind_plan_compact_unwind;
lldb::UnwindPlanSP m_unwind_plan_arm_unwind_sp;
lldb::UnwindPlanSP m_unwind_plan_fast_sp;
@@ -139,7 +148,9 @@ private:
// Fetching the UnwindPlans can be expensive - if we've already attempted
// to get one & failed, don't try again.
bool m_tried_unwind_plan_assembly : 1, m_tried_unwind_plan_eh_frame : 1,
+ m_tried_unwind_plan_debug_frame : 1,
m_tried_unwind_plan_eh_frame_augmented : 1,
+ m_tried_unwind_plan_debug_frame_augmented : 1,
m_tried_unwind_plan_compact_unwind : 1,
m_tried_unwind_plan_arm_unwind : 1, m_tried_unwind_fast : 1,
m_tried_unwind_arch_default : 1,
Modified: lldb/trunk/include/lldb/Symbol/UnwindTable.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/UnwindTable.h?rev=306397&r1=306396&r2=306397&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Symbol/UnwindTable.h (original)
+++ lldb/trunk/include/lldb/Symbol/UnwindTable.h Tue Jun 27 04:16:26 2017
@@ -27,6 +27,7 @@ public:
~UnwindTable();
lldb_private::DWARFCallFrameInfo *GetEHFrameInfo();
+ lldb_private::DWARFCallFrameInfo *GetDebugFrameInfo();
lldb_private::CompactUnwindInfo *GetCompactUnwindInfo();
@@ -58,6 +59,8 @@ private:
void Dump(Stream &s);
void Initialize();
+ llvm::Optional<AddressRange> GetAddressRange(const Address &addr,
+ SymbolContext &sc);
typedef std::map<lldb::addr_t, lldb::FuncUnwindersSP> collection;
typedef collection::iterator iterator;
@@ -70,6 +73,7 @@ private:
std::mutex m_mutex;
std::unique_ptr<DWARFCallFrameInfo> m_eh_frame_up;
+ std::unique_ptr<DWARFCallFrameInfo> m_debug_frame_up;
std::unique_ptr<CompactUnwindInfo> m_compact_unwind_up;
std::unique_ptr<ArmUnwindInfo> m_arm_unwind_up;
Modified: lldb/trunk/source/Commands/CommandObjectTarget.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectTarget.cpp?rev=306397&r1=306396&r2=306397&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectTarget.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectTarget.cpp Tue Jun 27 04:16:26 2017
@@ -3426,6 +3426,23 @@ protected:
result.GetOutputStream().Printf("\n");
}
+ if (UnwindPlanSP plan_sp =
+ func_unwinders_sp->GetDebugFrameUnwindPlan(*target, 0)) {
+ result.GetOutputStream().Printf("debug_frame UnwindPlan:\n");
+ plan_sp->Dump(result.GetOutputStream(), thread.get(),
+ LLDB_INVALID_ADDRESS);
+ result.GetOutputStream().Printf("\n");
+ }
+
+ if (UnwindPlanSP plan_sp =
+ func_unwinders_sp->GetDebugFrameAugmentedUnwindPlan(*target,
+ *thread, 0)) {
+ result.GetOutputStream().Printf("debug_frame augmented UnwindPlan:\n");
+ plan_sp->Dump(result.GetOutputStream(), thread.get(),
+ LLDB_INVALID_ADDRESS);
+ result.GetOutputStream().Printf("\n");
+ }
+
UnwindPlanSP arm_unwind_sp =
func_unwinders_sp->GetArmUnwindUnwindPlan(*target, 0);
if (arm_unwind_sp) {
Modified: lldb/trunk/source/Symbol/DWARFCallFrameInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/DWARFCallFrameInfo.cpp?rev=306397&r1=306396&r2=306397&view=diff
==============================================================================
--- lldb/trunk/source/Symbol/DWARFCallFrameInfo.cpp (original)
+++ lldb/trunk/source/Symbol/DWARFCallFrameInfo.cpp Tue Jun 27 04:16:26 2017
@@ -161,8 +161,6 @@ DWARFCallFrameInfo::DWARFCallFrameInfo(O
m_fde_index(), m_fde_index_initialized(false),
m_is_eh_frame(is_eh_frame) {}
-DWARFCallFrameInfo::~DWARFCallFrameInfo() {}
-
bool DWARFCallFrameInfo::GetUnwindPlan(Address addr, UnwindPlan &unwind_plan) {
FDEEntryMap::Entry fde_entry;
@@ -276,6 +274,12 @@ DWARFCallFrameInfo::ParseCIE(const dw_of
// cie.cieID = cieID;
cie_sp->ptr_encoding = DW_EH_PE_absptr; // default
cie_sp->version = m_cfi_data.GetU8(&offset);
+ if (cie_sp->version > CFI_VERSION4) {
+ Host::SystemLog(Host::eSystemLogError,
+ "CIE parse error: CFI version %d is not supported\n",
+ cie_sp->version);
+ return nullptr;
+ }
for (i = 0; i < CFI_AUG_MAX_SIZE; ++i) {
cie_sp->augmentation[i] = m_cfi_data.GetU8(&offset);
@@ -294,11 +298,23 @@ DWARFCallFrameInfo::ParseCIE(const dw_of
"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;
+ return nullptr;
+ }
+
+ // m_cfi_data uses address size from target architecture of the process
+ // may ignore these fields?
+ if (!m_is_eh_frame && cie_sp->version >= CFI_VERSION4) {
+ cie_sp->address_size = m_cfi_data.GetU8(&offset);
+ cie_sp->segment_size = m_cfi_data.GetU8(&offset);
}
+
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);
+
+ cie_sp->return_addr_reg_num =
+ !m_is_eh_frame && cie_sp->version >= CFI_VERSION3
+ ? static_cast<uint32_t>(m_cfi_data.GetULEB128(&offset))
+ : m_cfi_data.GetU8(&offset);
if (cie_sp->augmentation[0]) {
// Get the length of the eh_frame augmentation data
@@ -461,11 +477,33 @@ void DWARFCallFrameInfo::GetFDEIndex() {
m_fde_index_initialized = true;
return;
}
+
+ // An FDE entry contains CIE_pointer in debug_frame in same place as cie_id
+ // in eh_frame. CIE_pointer is an offset into the .debug_frame section.
+ // So, variable cie_offset should be equal to cie_id for debug_frame.
+ // FDE entries with cie_id == 0 shouldn't be ignored for it.
+ if ((cie_id == 0 && m_is_eh_frame) || cie_id == UINT32_MAX || len == 0) {
+ auto cie_sp = ParseCIE(current_entry);
+ if (!cie_sp) {
+ // Cannot parse, the reason is already logged
+ m_fde_index.Clear();
+ m_fde_index_initialized = true;
+ return;
+ }
+
+ m_cie_map[current_entry] = std::move(cie_sp);
+ offset = next_entry;
+ continue;
+ }
+
+ if (!m_is_eh_frame)
+ cie_offset = cie_id;
+
if (cie_offset > m_cfi_data.GetByteSize()) {
- Host::SystemLog(
- Host::eSystemLogError,
- "error: Invalid cie offset of 0x%x found in cie/fde at 0x%x\n",
- cie_offset, current_entry);
+ Host::SystemLog(Host::eSystemLogError,
+ "error: Invalid cie offset of 0x%x "
+ "found in cie/fde at 0x%x\n",
+ cie_offset, current_entry);
// Don't trust anything in this eh_frame section if we find blatantly
// invalid data.
m_fde_index.Clear();
@@ -473,12 +511,6 @@ void DWARFCallFrameInfo::GetFDEIndex() {
return;
}
- if (cie_id == 0 || cie_id == UINT32_MAX || len == 0) {
- m_cie_map[current_entry] = ParseCIE(current_entry);
- offset = next_entry;
- continue;
- }
-
const CIE *cie = GetCIE(cie_offset);
if (cie) {
const lldb::addr_t pc_rel_addr = m_section_sp->GetFileAddress();
@@ -531,7 +563,8 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan
cie_offset = m_cfi_data.GetU32(&offset);
}
- assert(cie_offset != 0 && cie_offset != UINT32_MAX);
+ // FDE entries with zeroth cie_offset may occur for debug_frame.
+ assert(!(m_is_eh_frame && 0 == cie_offset) && cie_offset != UINT32_MAX);
// Translate the CIE_id from the eh_frame format, which
// is relative to the FDE offset, into a __eh_frame section
Modified: lldb/trunk/source/Symbol/FuncUnwinders.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/FuncUnwinders.cpp?rev=306397&r1=306396&r2=306397&view=diff
==============================================================================
--- lldb/trunk/source/Symbol/FuncUnwinders.cpp (original)
+++ lldb/trunk/source/Symbol/FuncUnwinders.cpp Tue Jun 27 04:16:26 2017
@@ -39,7 +39,9 @@ FuncUnwinders::FuncUnwinders(UnwindTable
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),
@@ -56,17 +58,14 @@ UnwindPlanSP FuncUnwinders::GetUnwindPla
int current_offset) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
- UnwindPlanSP unwind_plan_sp = GetEHFrameUnwindPlan(target, current_offset);
- if (unwind_plan_sp)
- return unwind_plan_sp;
-
- unwind_plan_sp = GetCompactUnwindUnwindPlan(target, current_offset);
- if (unwind_plan_sp)
- return unwind_plan_sp;
-
- unwind_plan_sp = GetArmUnwindUnwindPlan(target, current_offset);
- if (unwind_plan_sp)
- return unwind_plan_sp;
+ 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;
}
@@ -121,6 +120,29 @@ UnwindPlanSP FuncUnwinders::GetEHFrameUn
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);
@@ -187,6 +209,48 @@ UnwindPlanSP FuncUnwinders::GetEHFrameAu
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) {
@@ -248,6 +312,8 @@ UnwindPlanSP FuncUnwinders::GetUnwindPla
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);
@@ -255,28 +321,22 @@ UnwindPlanSP FuncUnwinders::GetUnwindPla
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.
+ // 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.
+ // 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 &&
@@ -287,11 +347,12 @@ UnwindPlanSP FuncUnwinders::GetUnwindPla
return eh_frame_sp;
}
- UnwindPlanSP eh_frame_augmented_sp =
- GetEHFrameAugmentedUnwindPlan(target, thread, current_offset);
- if (eh_frame_augmented_sp) {
- return eh_frame_augmented_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;
}
Modified: lldb/trunk/source/Symbol/UnwindTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/UnwindTable.cpp?rev=306397&r1=306396&r2=306397&view=diff
==============================================================================
--- lldb/trunk/source/Symbol/UnwindTable.cpp (original)
+++ lldb/trunk/source/Symbol/UnwindTable.cpp Tue Jun 27 04:16:26 2017
@@ -44,38 +44,64 @@ void UnwindTable::Initialize() {
if (m_initialized) // check again once we've acquired the lock
return;
+ m_initialized = true;
SectionList *sl = m_object_file.GetSectionList();
- if (sl) {
- SectionSP sect = sl->FindSectionByType(eSectionTypeEHFrame, true);
- if (sect.get()) {
- m_eh_frame_up.reset(new DWARFCallFrameInfo(m_object_file, sect,
- eRegisterKindEHFrame, true));
- }
- sect = sl->FindSectionByType(eSectionTypeCompactUnwind, true);
- if (sect.get()) {
- m_compact_unwind_up.reset(new CompactUnwindInfo(m_object_file, sect));
- }
- sect = sl->FindSectionByType(eSectionTypeARMexidx, true);
- if (sect.get()) {
- SectionSP sect_extab = sl->FindSectionByType(eSectionTypeARMextab, true);
- if (sect_extab.get()) {
- m_arm_unwind_up.reset(
- new ArmUnwindInfo(m_object_file, sect, sect_extab));
- }
- }
+ if (!sl)
+ return;
+
+ SectionSP sect = sl->FindSectionByType(eSectionTypeEHFrame, true);
+ if (sect.get()) {
+ m_eh_frame_up.reset(new DWARFCallFrameInfo(m_object_file, sect,
+ eRegisterKindEHFrame, true));
}
- m_initialized = true;
+ sect = sl->FindSectionByType(eSectionTypeDWARFDebugFrame, true);
+ if (sect) {
+ m_debug_frame_up.reset(
+ new DWARFCallFrameInfo(m_object_file, sect, eRegisterKindDWARF, false));
+ }
+
+ sect = sl->FindSectionByType(eSectionTypeCompactUnwind, true);
+ if (sect) {
+ m_compact_unwind_up.reset(new CompactUnwindInfo(m_object_file, sect));
+ }
+
+ sect = sl->FindSectionByType(eSectionTypeARMexidx, true);
+ if (sect) {
+ SectionSP sect_extab = sl->FindSectionByType(eSectionTypeARMextab, true);
+ if (sect_extab.get()) {
+ m_arm_unwind_up.reset(new ArmUnwindInfo(m_object_file, sect, sect_extab));
+ }
+ }
}
UnwindTable::~UnwindTable() {}
+llvm::Optional<AddressRange> UnwindTable::GetAddressRange(const Address &addr,
+ SymbolContext &sc) {
+ AddressRange range;
+
+ // First check the symbol context
+ if (sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0,
+ false, range) &&
+ range.GetBaseAddress().IsValid())
+ return range;
+
+ // Does the eh_frame unwind info has a function bounds for this addr?
+ if (m_eh_frame_up && m_eh_frame_up->GetAddressRange(addr, range))
+ return range;
+
+ // Try debug_frame as well
+ if (m_debug_frame_up && m_debug_frame_up->GetAddressRange(addr, range))
+ return range;
+
+ return llvm::None;
+}
+
FuncUnwindersSP
UnwindTable::GetFuncUnwindersContainingAddress(const Address &addr,
SymbolContext &sc) {
- FuncUnwindersSP no_unwind_found;
-
Initialize();
std::lock_guard<std::mutex> guard(m_mutex);
@@ -96,23 +122,14 @@ UnwindTable::GetFuncUnwindersContainingA
return pos->second;
}
- AddressRange range;
- if (!sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0,
- false, range) ||
- !range.GetBaseAddress().IsValid()) {
- // Does the eh_frame unwind info has a function bounds for this addr?
- if (m_eh_frame_up == nullptr ||
- !m_eh_frame_up->GetAddressRange(addr, range)) {
- return no_unwind_found;
- }
- }
+ auto range_or = GetAddressRange(addr, sc);
+ if (!range_or)
+ return nullptr;
- FuncUnwindersSP func_unwinder_sp(new FuncUnwinders(*this, range));
+ FuncUnwindersSP func_unwinder_sp(new FuncUnwinders(*this, *range_or));
m_unwinds.insert(insert_pos,
- std::make_pair(range.GetBaseAddress().GetFileAddress(),
+ std::make_pair(range_or->GetBaseAddress().GetFileAddress(),
func_unwinder_sp));
- // StreamFile s(stdout, false);
- // Dump (s);
return func_unwinder_sp;
}
@@ -121,26 +138,16 @@ UnwindTable::GetFuncUnwindersContainingA
// UnwindTable. This is intended for use by target modules show-unwind where we
// want to create
// new UnwindPlans, not re-use existing ones.
-
FuncUnwindersSP
UnwindTable::GetUncachedFuncUnwindersContainingAddress(const Address &addr,
SymbolContext &sc) {
- FuncUnwindersSP no_unwind_found;
Initialize();
- AddressRange range;
- if (!sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0,
- false, range) ||
- !range.GetBaseAddress().IsValid()) {
- // Does the eh_frame unwind info has a function bounds for this addr?
- if (m_eh_frame_up == nullptr ||
- !m_eh_frame_up->GetAddressRange(addr, range)) {
- return no_unwind_found;
- }
- }
+ auto range_or = GetAddressRange(addr, sc);
+ if (!range_or)
+ return nullptr;
- FuncUnwindersSP func_unwinder_sp(new FuncUnwinders(*this, range));
- return func_unwinder_sp;
+ return std::make_shared<FuncUnwinders>(*this, *range_or);
}
void UnwindTable::Dump(Stream &s) {
@@ -161,6 +168,11 @@ DWARFCallFrameInfo *UnwindTable::GetEHFr
return m_eh_frame_up.get();
}
+DWARFCallFrameInfo *UnwindTable::GetDebugFrameInfo() {
+ Initialize();
+ return m_debug_frame_up.get();
+}
+
CompactUnwindInfo *UnwindTable::GetCompactUnwindInfo() {
Initialize();
return m_compact_unwind_up.get();
Modified: lldb/trunk/unittests/Symbol/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Symbol/CMakeLists.txt?rev=306397&r1=306396&r2=306397&view=diff
==============================================================================
--- lldb/trunk/unittests/Symbol/CMakeLists.txt (original)
+++ lldb/trunk/unittests/Symbol/CMakeLists.txt Tue Jun 27 04:16:26 2017
@@ -1,8 +1,16 @@
add_lldb_unittest(SymbolTests
TestClangASTContext.cpp
+ TestDWARFCallFrameInfo.cpp
TestType.cpp
LINK_LIBS
lldbHost
lldbSymbol
)
+
+add_dependencies(SymbolTests yaml2obj)
+add_definitions(-DYAML2OBJ="$<TARGET_FILE:yaml2obj>")
+set(test_inputs
+ basic-call-frame-info.yaml
+ )
+add_unittest_inputs(SymbolTests "${test_inputs}")
Added: lldb/trunk/unittests/Symbol/Inputs/basic-call-frame-info.yaml
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Symbol/Inputs/basic-call-frame-info.yaml?rev=306397&view=auto
==============================================================================
--- lldb/trunk/unittests/Symbol/Inputs/basic-call-frame-info.yaml (added)
+++ lldb/trunk/unittests/Symbol/Inputs/basic-call-frame-info.yaml Tue Jun 27 04:16:26 2017
@@ -0,0 +1,138 @@
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_DYN
+ Machine: EM_X86_64
+ Entry: 0x0000000000000260
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ Address: 0x0000000000000260
+ AddressAlign: 0x0000000000000010
+ Content: 554889E5897DFC8B45FC5DC30F1F4000554889E5897DFC8B45FC5DC30F1F4000554889E5897DFC8B45FC5DC3
+#0000000000000260 <eh_frame>:
+# 260: 55 push %rbp
+# 261: 48 89 e5 mov %rsp,%rbp
+# 264: 89 7d fc mov %edi,-0x4(%rbp)
+# 267: 8b 45 fc mov -0x4(%rbp),%eax
+# 26a: 5d pop %rbp
+# 26b: c3 retq
+# 26c: 0f 1f 40 00 nopl 0x0(%rax)
+#
+#0000000000000270 <debug_frame3>:
+# 270: 55 push %rbp
+# 271: 48 89 e5 mov %rsp,%rbp
+# 274: 89 7d fc mov %edi,-0x4(%rbp)
+# 277: 8b 45 fc mov -0x4(%rbp),%eax
+# 27a: 5d pop %rbp
+# 27b: c3 retq
+# 27c: 0f 1f 40 00 nopl 0x0(%rax)
+#
+#0000000000000280 <debug_frame4>:
+# 280: 55 push %rbp
+# 281: 48 89 e5 mov %rsp,%rbp
+# 284: 89 7d fc mov %edi,-0x4(%rbp)
+# 287: 8b 45 fc mov -0x4(%rbp),%eax
+# 28a: 5d pop %rbp
+# 28b: c3 retq
+ - Name: .eh_frame
+ Type: SHT_X86_64_UNWIND
+ Flags: [ SHF_ALLOC ]
+ Address: 0x0000000000000290
+ AddressAlign: 0x0000000000000008
+ Content: 1400000000000000017A5200017810011B0C0708900100001C0000001C000000B0FFFFFF0C00000000410E108602430D0600000000000000
+#00000000 0000000000000014 00000000 CIE
+# Version: 1
+# Augmentation: "zR"
+# Code alignment factor: 1
+# Data alignment factor: -8
+# Return address column: 16
+# Augmentation data: 1b
+#
+# DW_CFA_def_cfa: r7 (rsp) ofs 8
+# DW_CFA_offset: r16 (rip) at cfa-8
+# DW_CFA_nop
+# DW_CFA_nop
+#
+#00000018 000000000000001c 0000001c FDE cie=00000000 pc=ffffffffffffffd0..ffffffffffffffdc
+# DW_CFA_advance_loc: 1 to ffffffffffffffd1
+# DW_CFA_def_cfa_offset: 16
+# DW_CFA_offset: r6 (rbp) at cfa-16
+# DW_CFA_advance_loc: 3 to ffffffffffffffd4
+# DW_CFA_def_cfa_register: r6 (rbp)
+# DW_CFA_nop
+# DW_CFA_nop
+# DW_CFA_nop
+# DW_CFA_nop
+# DW_CFA_nop
+# DW_CFA_nop
+# DW_CFA_nop
+ - Name: .debug_frame
+ Type: SHT_PROGBITS
+ AddressAlign: 0x0000000000000008
+ Content: 14000000FFFFFFFF03000178100C070890010000000000001C0000000000000070020000000000000C00000000000000410E108602430D0614000000FFFFFFFF040008000178100C07089001000000001C0000003800000080020000000000000C00000000000000410E108602430D06
+#00000000 0000000000000014 ffffffff CIE
+# Version: 3
+# Augmentation: ""
+# Code alignment factor: 1
+# Data alignment factor: -8
+# Return address column: 16
+#
+# DW_CFA_def_cfa: r7 (rsp) ofs 8
+# DW_CFA_offset: r16 (rip) at cfa-8
+# DW_CFA_nop
+# DW_CFA_nop
+# DW_CFA_nop
+# DW_CFA_nop
+# DW_CFA_nop
+# DW_CFA_nop
+#
+#00000018 000000000000001c 00000000 FDE cie=00000000 pc=0000000000000270..000000000000027c
+# DW_CFA_advance_loc: 1 to 0000000000000271
+# DW_CFA_def_cfa_offset: 16
+# DW_CFA_offset: r6 (rbp) at cfa-16
+# DW_CFA_advance_loc: 3 to 0000000000000274
+# DW_CFA_def_cfa_register: r6 (rbp)
+#
+#00000038 0000000000000014 ffffffff CIE
+# Version: 4
+# Augmentation: ""
+# Pointer Size: 8
+# Segment Size: 0
+# Code alignment factor: 1
+# Data alignment factor: -8
+# Return address column: 16
+#
+# DW_CFA_def_cfa: r7 (rsp) ofs 8
+# DW_CFA_offset: r16 (rip) at cfa-8
+# DW_CFA_nop
+# DW_CFA_nop
+# DW_CFA_nop
+# DW_CFA_nop
+#
+#00000050 000000000000001c 00000038 FDE cie=00000038 pc=0000000000000280..000000000000028c
+# DW_CFA_advance_loc: 1 to 0000000000000281
+# DW_CFA_def_cfa_offset: 16
+# DW_CFA_offset: r6 (rbp) at cfa-16
+# DW_CFA_advance_loc: 3 to 0000000000000284
+# DW_CFA_def_cfa_register: r6 (rbp)
+Symbols:
+ Global:
+ - Name: eh_frame
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000260
+ Size: 0x000000000000000C
+ - Name: debug_frame3
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000270
+ Size: 0x000000000000000C
+ - Name: debug_frame4
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000280
+ Size: 0x000000000000000C
+...
Added: lldb/trunk/unittests/Symbol/TestDWARFCallFrameInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Symbol/TestDWARFCallFrameInfo.cpp?rev=306397&view=auto
==============================================================================
--- lldb/trunk/unittests/Symbol/TestDWARFCallFrameInfo.cpp (added)
+++ lldb/trunk/unittests/Symbol/TestDWARFCallFrameInfo.cpp Tue Jun 27 04:16:26 2017
@@ -0,0 +1,147 @@
+//===-- TestDWARFCallFrameInfo.cpp ------------------------------*- C++ -*-===//
+//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
+#include "Plugins/Process/Utility/RegisterContext_x86.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Symbol/DWARFCallFrameInfo.h"
+#include "lldb/Utility/StreamString.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/raw_ostream.h"
+#include "gtest/gtest.h"
+
+extern const char *TestMainArgv0;
+
+using namespace lldb_private;
+using namespace lldb;
+
+class DWARFCallFrameInfoTest : public testing::Test {
+public:
+ void SetUp() override {
+ HostInfo::Initialize();
+ ObjectFileELF::Initialize();
+
+ m_inputs_folder = llvm::sys::path::parent_path(TestMainArgv0);
+ llvm::sys::path::append(m_inputs_folder, "Inputs");
+ llvm::sys::fs::make_absolute(m_inputs_folder);
+ }
+
+ void TearDown() override {
+ ObjectFileELF::Terminate();
+ HostInfo::Terminate();
+ }
+
+protected:
+ llvm::SmallString<128> m_inputs_folder;
+
+ void TestBasic(bool eh_frame, llvm::StringRef symbol);
+};
+
+#define ASSERT_NO_ERROR(x) \
+ if (std::error_code ASSERT_NO_ERROR_ec = x) { \
+ llvm::SmallString<128> MessageStorage; \
+ llvm::raw_svector_ostream Message(MessageStorage); \
+ Message << #x ": did not return errc::success.\n" \
+ << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n" \
+ << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \
+ GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \
+ } else { \
+ }
+
+namespace lldb_private {
+static std::ostream &operator<<(std::ostream &OS, const UnwindPlan::Row &row) {
+ StreamString SS;
+ row.Dump(SS, nullptr, nullptr, 0);
+ return OS << SS.GetData();
+}
+} // namespace lldb_private
+
+static UnwindPlan::Row GetExpectedRow0() {
+ UnwindPlan::Row row;
+ row.SetOffset(0);
+ row.GetCFAValue().SetIsRegisterPlusOffset(dwarf_rsp_x86_64, 8);
+ row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rip_x86_64, -8, false);
+ return row;
+}
+
+static UnwindPlan::Row GetExpectedRow1() {
+ UnwindPlan::Row row;
+ row.SetOffset(1);
+ row.GetCFAValue().SetIsRegisterPlusOffset(dwarf_rsp_x86_64, 16);
+ row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rip_x86_64, -8, false);
+ row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rbp_x86_64, -16, false);
+ return row;
+}
+
+static UnwindPlan::Row GetExpectedRow2() {
+ UnwindPlan::Row row;
+ row.SetOffset(4);
+ row.GetCFAValue().SetIsRegisterPlusOffset(dwarf_rbp_x86_64, 16);
+ row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rip_x86_64, -8, false);
+ row.SetRegisterLocationToAtCFAPlusOffset(dwarf_rbp_x86_64, -16, false);
+ return row;
+}
+
+void DWARFCallFrameInfoTest::TestBasic(bool eh_frame, llvm::StringRef symbol) {
+ llvm::SmallString<128> yaml = m_inputs_folder;
+ llvm::sys::path::append(yaml, "basic-call-frame-info.yaml");
+ llvm::SmallString<128> obj = m_inputs_folder;
+
+ ASSERT_NO_ERROR(llvm::sys::fs::createTemporaryFile(
+ "basic-call-frame-info-%%%%%%", "obj", obj));
+ llvm::FileRemover obj_remover(obj);
+
+ const char *args[] = {YAML2OBJ, yaml.c_str(), nullptr};
+ llvm::StringRef obj_ref = obj;
+ const llvm::StringRef *redirects[] = {nullptr, &obj_ref, nullptr};
+ ASSERT_EQ(0, llvm::sys::ExecuteAndWait(YAML2OBJ, args, nullptr, redirects));
+
+ uint64_t size;
+ ASSERT_NO_ERROR(llvm::sys::fs::file_size(obj, size));
+ ASSERT_GT(size, 0u);
+
+ auto module_sp = std::make_shared<Module>(ModuleSpec(FileSpec(obj, false)));
+ SectionList *list = module_sp->GetSectionList();
+ ASSERT_NE(nullptr, list);
+
+ auto section_sp = list->FindSectionByType(
+ eh_frame ? eSectionTypeEHFrame : eSectionTypeDWARFDebugFrame, false);
+ ASSERT_NE(nullptr, section_sp);
+
+ DWARFCallFrameInfo cfi(*module_sp->GetObjectFile(), section_sp,
+ eh_frame ? eRegisterKindEHFrame : eRegisterKindDWARF,
+ eh_frame);
+
+ const Symbol *sym = module_sp->FindFirstSymbolWithNameAndType(
+ ConstString(symbol), eSymbolTypeAny);
+ ASSERT_NE(nullptr, sym);
+
+ UnwindPlan plan(eRegisterKindGeneric);
+ ASSERT_TRUE(cfi.GetUnwindPlan(sym->GetAddress(), plan));
+ ASSERT_EQ(3, plan.GetRowCount());
+ EXPECT_EQ(GetExpectedRow0(), *plan.GetRowAtIndex(0));
+ EXPECT_EQ(GetExpectedRow1(), *plan.GetRowAtIndex(1));
+ EXPECT_EQ(GetExpectedRow2(), *plan.GetRowAtIndex(2));
+}
+
+TEST_F(DWARFCallFrameInfoTest, Basic_dwarf3) {
+ TestBasic(false, "debug_frame3");
+}
+
+TEST_F(DWARFCallFrameInfoTest, Basic_dwarf4) {
+ TestBasic(false, "debug_frame4");
+}
+
+TEST_F(DWARFCallFrameInfoTest, Basic_eh) { TestBasic(true, "eh_frame"); }
More information about the lldb-commits
mailing list