summaryrefslogtreecommitdiffstats
path: root/lldb/source/Symbol
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Symbol')
-rw-r--r--lldb/source/Symbol/DWARFCallFrameInfo.cpp966
-rw-r--r--lldb/source/Symbol/FuncUnwinders.cpp126
-rw-r--r--lldb/source/Symbol/UnwindPlan.cpp309
-rw-r--r--lldb/source/Symbol/UnwindTable.cpp132
4 files changed, 744 insertions, 789 deletions
diff --git a/lldb/source/Symbol/DWARFCallFrameInfo.cpp b/lldb/source/Symbol/DWARFCallFrameInfo.cpp
index 4b6d19f1524..b5da066006c 100644
--- a/lldb/source/Symbol/DWARFCallFrameInfo.cpp
+++ b/lldb/source/Symbol/DWARFCallFrameInfo.cpp
@@ -12,8 +12,7 @@
// C++ Includes
#include <list>
-// Other libraries and framework includes
-// Project includes
+#include "lldb/Core/Section.h"
#include "lldb/Symbol/DWARFCallFrameInfo.h"
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/Module.h"
@@ -21,413 +20,83 @@
#include "lldb/Target/RegisterContext.h"
#include "lldb/Core/Section.h"
#include "lldb/Target/Thread.h"
+#include "lldb/Symbol/UnwindPlan.h"
using namespace lldb;
using namespace lldb_private;
-static void
-DumpRegisterName (Stream *s, Thread *thread, const ArchSpec *arch, uint32_t reg_kind, uint32_t reg_num)
+DWARFCallFrameInfo::DWARFCallFrameInfo(ObjectFile& objfile, SectionSP& section, uint32_t reg_kind, bool is_eh_frame) :
+ m_objfile (objfile),
+ m_section (section),
+ m_reg_kind (reg_kind), // The flavor of registers that the CFI data uses (enum RegisterKind)
+ m_cie_map (),
+ m_cfi_data (),
+ m_cfi_data_initialized (false),
+ m_fde_index (),
+ m_fde_index_initialized (false),
+ m_is_eh_frame (is_eh_frame)
{
- const char *reg_name = NULL;
- RegisterContext *reg_ctx = NULL;
- if (thread)
- {
- reg_ctx = thread->GetRegisterContext();
- if (reg_ctx)
- reg_name = reg_ctx->GetRegisterName (reg_ctx->ConvertRegisterKindToRegisterNumber (reg_kind, reg_num));
- }
-
- if (reg_name == NULL && arch != NULL)
- {
- switch (reg_kind)
- {
- case eRegisterKindDWARF: reg_name = arch->GetRegisterName(reg_num, eRegisterKindDWARF); break;
- case eRegisterKindGCC: reg_name = arch->GetRegisterName(reg_num, eRegisterKindGCC); break;
- default:
- break;
- }
- }
-
- if (reg_name)
- s->PutCString(reg_name);
- else
- {
- const char *reg_kind_name = NULL;
- switch (reg_kind)
- {
- case eRegisterKindDWARF: reg_kind_name = "dwarf-reg"; break;
- case eRegisterKindGCC: reg_kind_name = "compiler-reg"; break;
- case eRegisterKindGeneric: reg_kind_name = "generic-reg"; break;
- default:
- break;
- }
- if (reg_kind_name)
- s->Printf("%s(%u)", reg_kind_name, reg_num);
- else
- s->Printf("reg(%d.%u)", reg_kind, reg_num);
- }
}
-
-#pragma mark DWARFCallFrameInfo::RegisterLocation
-
-DWARFCallFrameInfo::RegisterLocation::RegisterLocation() :
- m_type(isSame)
+DWARFCallFrameInfo::~DWARFCallFrameInfo()
{
}
bool
-DWARFCallFrameInfo::RegisterLocation::operator == (const DWARFCallFrameInfo::RegisterLocation& rhs) const
+DWARFCallFrameInfo::GetAddressRange (Address addr, AddressRange &range)
{
- if (m_type != rhs.m_type)
+ FDEEntry fde_entry;
+ if (GetFDEEntryByAddress (addr, fde_entry) == false)
return false;
- switch (m_type)
- {
- case unspecified:
- case isUndefined:
- case isSame:
- return true;
-
- case atCFAPlusOffset:
- return m_location.offset == rhs.m_location.offset;
-
- case isCFAPlusOffset:
- return m_location.offset == rhs.m_location.offset;
-
- case inOtherRegister:
- return m_location.reg_num == rhs.m_location.reg_num;
-
- default:
- break;
- }
- return false;
-}
-
-void
-DWARFCallFrameInfo::RegisterLocation::SetUnspecified()
-{
- m_type = unspecified;
-}
-
-void
-DWARFCallFrameInfo::RegisterLocation::SetUndefined()
-{
- m_type = isUndefined;
+ range = fde_entry.bounds;
+ return true;
}
-void
-DWARFCallFrameInfo::RegisterLocation::SetSame()
-{
- m_type = isSame;
-}
-
-void
-DWARFCallFrameInfo::RegisterLocation::SetAtCFAPlusOffset(int64_t offset)
-{
- m_type = atCFAPlusOffset;
- m_location.offset = offset;
-}
-
-void
-DWARFCallFrameInfo::RegisterLocation::SetIsCFAPlusOffset(int64_t offset)
-{
- m_type = isCFAPlusOffset;
- m_location.offset = offset;
-}
-
-void
-DWARFCallFrameInfo::RegisterLocation::SetInRegister (uint32_t reg_num)
-{
- m_type = inOtherRegister;
- m_location.reg_num = reg_num;
-}
-
-void
-DWARFCallFrameInfo::RegisterLocation::SetAtDWARFExpression(const uint8_t *opcodes, uint32_t len)
-{
- m_type = atDWARFExpression;
- m_location.expr.opcodes = opcodes;
- m_location.expr.length = len;
-}
-
-void
-DWARFCallFrameInfo::RegisterLocation::SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len)
-{
- m_type = isDWARFExpression;
- m_location.expr.opcodes = opcodes;
- m_location.expr.length = len;
-}
-
-void
-DWARFCallFrameInfo::RegisterLocation::Dump(Stream *s, const DWARFCallFrameInfo &cfi, Thread *thread, const Row *row, uint32_t reg_num) const
-{
- const ArchSpec *arch = cfi.GetArchitecture();
- const uint32_t reg_kind = cfi.GetRegisterKind();
-
- DumpRegisterName (s, thread, arch, reg_kind, reg_num);
- s->PutChar('=');
-
- switch (m_type)
- {
- case unspecified:
- s->PutChar('?');
- break;
-
- case isUndefined:
- s->PutCString("undefined");
- break;
-
- case isSame:
- s->PutCString("same");
- break;
-
- case atCFAPlusOffset:
- s->PutChar('[');
- // Fall through to isCFAPlusOffset...
- case isCFAPlusOffset:
- {
- DumpRegisterName (s, thread, arch, reg_kind, row->GetCFARegister());
- int32_t offset = row->GetCFAOffset() + m_location.offset;
- if (offset != 0)
- s->Printf("%-+d", offset);
- if (m_type == atCFAPlusOffset)
- s->PutChar(']');
- }
- break;
-
- case inOtherRegister:
- DumpRegisterName (s, thread, arch, reg_kind, m_location.reg_num);
- break;
-
- case atDWARFExpression:
- s->PutCString("[EXPR] ");
- break;
-
- case isDWARFExpression:
- s->PutCString("EXPR ");
- break;
- }
-}
-
-
-#pragma mark DWARFCallFrameInfo::Row
-
-DWARFCallFrameInfo::Row::Row() :
- m_offset(0),
- m_cfa_reg_num(0),
- m_cfa_offset(0),
- m_register_locations()
-{
-}
-
-DWARFCallFrameInfo::Row::~Row()
+bool
+DWARFCallFrameInfo::GetUnwindPlan (Address addr, UnwindPlan& unwind_plan)
{
+ FDEEntry fde_entry;
+ if (GetFDEEntryByAddress (addr, fde_entry) == false)
+ return false;
+ return FDEToUnwindPlan (fde_entry.offset, addr, unwind_plan);
}
-void
-DWARFCallFrameInfo::Row::Clear()
-{
- m_register_locations.clear();
-}
bool
-DWARFCallFrameInfo::Row::GetRegisterInfo (uint32_t reg_num, DWARFCallFrameInfo::RegisterLocation& register_location) const
+DWARFCallFrameInfo::GetFDEEntryByAddress (Address addr, FDEEntry& fde_entry)
{
- collection::const_iterator pos = m_register_locations.find(reg_num);
- if (pos != m_register_locations.end())
- {
- register_location = pos->second;
- return true;
- }
- return false;
-}
+ if (m_section.get() == NULL)
+ return false;
+ GetFDEIndex();
-void
-DWARFCallFrameInfo::Row::SetRegisterInfo (uint32_t reg_num, const RegisterLocation& register_location)
-{
- m_register_locations[reg_num] = register_location;
-}
+ struct FDEEntry searchfde;
+ searchfde.bounds = AddressRange (addr, 1);
+ std::vector<FDEEntry>::const_iterator idx;
+ if (m_fde_index.size() == 0)
+ return false;
-void
-DWARFCallFrameInfo::Row::Dump(Stream* s, const DWARFCallFrameInfo &cfi, Thread *thread, lldb::addr_t base_addr) const
-{
- const ArchSpec *arch = cfi.GetArchitecture();
- const uint32_t reg_kind = cfi.GetRegisterKind();
- collection::const_iterator pos, end = m_register_locations.end();
- s->Indent();
- s->Printf("0x%16.16llx: CFA=", m_offset + base_addr);
- DumpRegisterName(s, thread, arch, reg_kind, m_cfa_reg_num);
- if (m_cfa_offset != 0)
- s->Printf("%-+lld", m_cfa_offset);
-
- for (pos = m_register_locations.begin(); pos != end; ++pos)
+ idx = std::lower_bound (m_fde_index.begin(), m_fde_index.end(), searchfde);
+ if (idx == m_fde_index.end())
{
- s->PutChar(' ');
- pos->second.Dump(s, cfi, thread, this, pos->first);
+ --idx;
}
- s->EOL();
-}
-
-
-#pragma mark DWARFCallFrameInfo::FDE
-
-
-DWARFCallFrameInfo::FDE::FDE (dw_offset_t offset, const AddressRange &range) :
- m_fde_offset (offset),
- m_range (range),
- m_row_list ()
-{
-}
-
-DWARFCallFrameInfo::FDE::~FDE()
-{
-}
-
-void
-DWARFCallFrameInfo::FDE::AppendRow (const Row &row)
-{
- if (m_row_list.empty() || m_row_list.back().GetOffset() != row.GetOffset())
- m_row_list.push_back(row);
- else
- m_row_list.back() = row;
-}
-
-void
-DWARFCallFrameInfo::FDE::Dump (Stream *s, const DWARFCallFrameInfo &cfi, Thread* thread) const
-{
- s->Indent();
- s->Printf("FDE{0x%8.8x} ", m_fde_offset);
- m_range.Dump(s, NULL, Address::DumpStyleFileAddress);
- lldb::addr_t fde_base_addr = m_range.GetBaseAddress().GetFileAddress();
- s->EOL();
- s->IndentMore();
- collection::const_iterator pos, end = m_row_list.end();
- for (pos = m_row_list.begin(); pos != end; ++pos)
+ if (idx != m_fde_index.begin() && idx->bounds.GetBaseAddress().GetOffset() != addr.GetOffset())
{
- pos->Dump(s, cfi, thread, fde_base_addr);
+ --idx;
}
- s->IndentLess();
-}
-
-const AddressRange &
-DWARFCallFrameInfo::FDE::GetAddressRange() const
-{
- return m_range;
-}
-
-bool
-DWARFCallFrameInfo::FDE::IsValidRowIndex (uint32_t idx) const
-{
- return idx < m_row_list.size();
-}
-
-const DWARFCallFrameInfo::Row&
-DWARFCallFrameInfo::FDE::GetRowAtIndex (uint32_t idx)
-{
- // You must call IsValidRowIndex(idx) first before calling this!!!
- return m_row_list[idx];
-}
-#pragma mark DWARFCallFrameInfo::FDEInfo
-
-DWARFCallFrameInfo::FDEInfo::FDEInfo () :
- fde_offset (0),
- fde_sp()
-{
-}
-
-DWARFCallFrameInfo::FDEInfo::FDEInfo (off_t offset) :
- fde_offset(offset),
- fde_sp()
-{
-}
-
-#pragma mark DWARFCallFrameInfo::CIE
-
-DWARFCallFrameInfo::CIE::CIE(dw_offset_t offset) :
- cie_offset (offset),
- version (0),
- augmentation(),
- code_align (0),
- data_align (0),
- return_addr_reg_num (0),
- inst_offset (0),
- inst_length (0),
- ptr_encoding (DW_EH_PE_absptr)
-{
-}
-
-
-DWARFCallFrameInfo::CIE::~CIE()
-{
-}
-
-void
-DWARFCallFrameInfo::CIE::Dump(Stream *s, Thread* thread, const ArchSpec *arch, uint32_t reg_kind) const
-{
- s->Indent();
- s->Printf("CIE{0x%8.8x} version=%u, code_align=%u, data_align=%d, return_addr_reg=", cie_offset, version, code_align, data_align);
- DumpRegisterName(s, thread, arch, reg_kind, return_addr_reg_num);
- s->Printf(", instr_offset=0x%8.8x, instr_length=%u, ptr_encoding=0x%02x\n",
- inst_offset,
- inst_length,
- ptr_encoding);
-}
-
-#pragma mark DWARFCallFrameInfo::CIE
-
-DWARFCallFrameInfo::DWARFCallFrameInfo(ObjectFile *objfile, Section *section, uint32_t reg_kind) :
- m_objfile (objfile),
- m_section (section),
- m_reg_kind (reg_kind), // The flavor of registers that the CFI data uses (One of the defines that starts with "LLDB_REGKIND_")
- m_cfi_data (),
- m_cie_map (),
- m_fde_map ()
-{
- if (objfile && section)
+ if (idx->bounds.ContainsFileAddress (addr))
{
- section->ReadSectionDataFromObjectFile (objfile, m_cfi_data);
+ fde_entry = *idx;
+ return true;
}
-}
-
-DWARFCallFrameInfo::~DWARFCallFrameInfo()
-{
-}
-
-bool
-DWARFCallFrameInfo::IsEHFrame() const
-{
- return (m_reg_kind == eRegisterKindGCC);
-}
-
-const ArchSpec *
-DWARFCallFrameInfo::GetArchitecture() const
-{
- if (m_objfile && m_objfile->GetModule())
- return &m_objfile->GetModule()->GetArchitecture();
- return NULL;
-}
-uint32_t
-DWARFCallFrameInfo::GetRegisterKind () const
-{
- return m_reg_kind;
-}
-
-void
-DWARFCallFrameInfo::SetRegisterKind (uint32_t reg_kind)
-{
- m_reg_kind = reg_kind;
+ return false;
}
-
-
-
const DWARFCallFrameInfo::CIE*
DWARFCallFrameInfo::GetCIE(dw_offset_t cie_offset)
{
- Index ();
-
cie_map_t::iterator pos = m_cie_map.find(cie_offset);
if (pos != m_cie_map.end())
@@ -441,16 +110,20 @@ DWARFCallFrameInfo::GetCIE(dw_offset_t cie_offset)
return NULL;
}
-DWARFCallFrameInfo::CIE::shared_ptr
+DWARFCallFrameInfo::CIESP
DWARFCallFrameInfo::ParseCIE (const dw_offset_t cie_offset)
{
- CIE::shared_ptr cie_sp(new CIE(cie_offset));
- const bool for_eh_frame = IsEHFrame();
+ CIESP cie_sp(new CIE(cie_offset));
dw_offset_t offset = cie_offset;
+ if (m_cfi_data_initialized == false)
+ {
+ m_section->ReadSectionDataFromObjectFile (&m_objfile, m_cfi_data);
+ m_cfi_data_initialized = true;
+ }
const uint32_t length = m_cfi_data.GetU32(&offset);
const dw_offset_t cie_id = m_cfi_data.GetU32(&offset);
const dw_offset_t end_offset = cie_offset + length + 4;
- if (length > 0 && (!for_eh_frame && cie_id == 0xfffffffful) || (for_eh_frame && cie_id == 0ul))
+ if (length > 0 && (!m_is_eh_frame && cie_id == 0xfffffffful) || (m_is_eh_frame && cie_id == 0ul))
{
size_t i;
// cie.offset = cie_offset;
@@ -555,164 +228,158 @@ DWARFCallFrameInfo::ParseCIE (const dw_offset_t cie_offset)
cie_sp->inst_offset = offset;
cie_sp->inst_length = end_offset - offset;
}
+ while (offset < end_offset)
+ {
+ uint8_t inst = m_cfi_data.GetU8(&offset);
+ uint8_t primary_opcode = inst & 0xC0;
+ uint8_t extended_opcode = inst & 0x3F;
+
+ if (extended_opcode == DW_CFA_def_cfa)
+ {
+ // Takes two unsigned LEB128 operands representing a register
+ // number and a (non-factored) offset. The required action
+ // is to define the current CFA rule to use the provided
+ // register and offset.
+ uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ int op_offset = (int32_t)m_cfi_data.GetULEB128(&offset);
+ cie_sp->initial_row.SetCFARegister (reg_num);
+ cie_sp->initial_row.SetCFAOffset (op_offset);
+ continue;
+ }
+ if (primary_opcode == DW_CFA_offset)
+ {
+ // 0x80 - high 2 bits are 0x2, lower 6 bits are register.
+ // Takes two arguments: an unsigned LEB128 constant representing a
+ // factored offset and a register number. The required action is to
+ // change the rule for the register indicated by the register number
+ // to be an offset(N) rule with a value of
+ // (N = factored offset * data_align).
+ uint32_t reg_num = extended_opcode;
+ int op_offset = (int32_t)m_cfi_data.GetULEB128(&offset) * cie_sp->data_align;
+ UnwindPlan::Row::RegisterLocation reg_location;
+ reg_location.SetAtCFAPlusOffset(op_offset);
+ cie_sp->initial_row.SetRegisterInfo (reg_num, reg_location);
+ continue;
+ }
+ if (extended_opcode == DW_CFA_nop)
+ {
+ continue;
+ }
+ break; // Stop if we hit an unrecognized opcode
+ }
}
return cie_sp;
}
-DWARFCallFrameInfo::FDE::shared_ptr
-DWARFCallFrameInfo::ParseFDE(const dw_offset_t fde_offset)
+// Scan through the eh_frame or debug_frame section looking for FDEs and noting the start/end addresses
+// of the functions and a pointer back to the function's FDE for later expansion.
+// Internalize CIEs as we come across them.
+
+void
+DWARFCallFrameInfo::GetFDEIndex ()
{
- const bool for_eh_frame = IsEHFrame();
- FDE::shared_ptr fde_sp;
+ if (m_section.get() == NULL)
+ return;
+ if (m_fde_index_initialized)
+ return;
- dw_offset_t offset = fde_offset;
- const uint32_t length = m_cfi_data.GetU32(&offset);
- dw_offset_t cie_offset = m_cfi_data.GetU32(&offset);
- const dw_offset_t end_offset = fde_offset + length + 4;
+ dw_offset_t offset = 0;
+ if (m_cfi_data_initialized == false)
+ {
+ m_section->ReadSectionDataFromObjectFile (&m_objfile, m_cfi_data);
+ m_cfi_data_initialized = true;
+ }
+ while (m_cfi_data.ValidOffsetForDataOfSize (offset, 8))
+ {
+ dw_offset_t current_entry = offset;
+ uint32_t len = m_cfi_data.GetU32 (&offset);
+ dw_offset_t next_entry = current_entry + len + 4;
+ dw_offset_t cie_id = m_cfi_data.GetU32 (&offset);
- // Translate the CIE_id from the eh_frame format, which
- // is relative to the FDE offset, into a __eh_frame section
- // offset
- if (for_eh_frame)
- cie_offset = offset - (cie_offset + 4);
+ if (cie_id == 0 || cie_id == UINT32_MAX)
+ {
+ m_cie_map[current_entry] = ParseCIE (current_entry);
+ offset = next_entry;
+ continue;
+ }
+
+ const CIE *cie = GetCIE (current_entry + 4 - cie_id);
+ assert (cie != NULL);
- const CIE* cie = GetCIE(cie_offset);
- if (cie)
- {
const lldb::addr_t pc_rel_addr = m_section->GetFileAddress();
const lldb::addr_t text_addr = LLDB_INVALID_ADDRESS;
const lldb::addr_t data_addr = LLDB_INVALID_ADDRESS;
- lldb::addr_t range_base = m_cfi_data.GetGNUEHPointer(&offset, cie->ptr_encoding, pc_rel_addr, text_addr, data_addr);
- lldb::addr_t range_len = m_cfi_data.GetGNUEHPointer(&offset, cie->ptr_encoding & DW_EH_PE_MASK_ENCODING, pc_rel_addr, text_addr, data_addr);
- if (cie->augmentation[0] == 'z')
- {
- uint32_t aug_data_len = (uint32_t)m_cfi_data.GetULEB128(&offset);
- offset += aug_data_len;
- }
+ lldb::addr_t addr = m_cfi_data.GetGNUEHPointer(&offset, cie->ptr_encoding, pc_rel_addr, text_addr, data_addr);
+ lldb::addr_t length = m_cfi_data.GetGNUEHPointer(&offset, cie->ptr_encoding & DW_EH_PE_MASK_ENCODING, pc_rel_addr, text_addr, data_addr);
+ FDEEntry fde;
+ fde.bounds = AddressRange (addr, length, m_objfile.GetSectionList());
+ fde.offset = current_entry;
+ m_fde_index.push_back(fde);
- AddressRange fde_range (range_base, range_len, m_objfile->GetSectionList ());
- fde_sp.reset(new FDE(fde_offset, fde_range));
- if (offset < end_offset)
- {
- dw_offset_t fde_instr_offset = offset;
- uint32_t fde_instr_length = end_offset - offset;
- if (cie->inst_length > 0)
- ParseInstructions(cie, fde_sp.get(), cie->inst_offset, cie->inst_length);
- ParseInstructions(cie, fde_sp.get(), fde_instr_offset, fde_instr_length);
- }
+ offset = next_entry;
}
- return fde_sp;
+ std::sort (m_fde_index.begin(), m_fde_index.end());
+ m_fde_index_initialized = true;
}
-const DWARFCallFrameInfo::FDE *
-DWARFCallFrameInfo::FindFDE(const Address &addr)
+bool
+DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t offset, Address startaddr, UnwindPlan& unwind_plan)
{
- Index ();
+ dw_offset_t current_entry = offset;
- VMRange find_range(addr.GetFileAddress(), 0);
- fde_map_t::iterator pos = m_fde_map.lower_bound (find_range);
- fde_map_t::iterator end = m_fde_map.end();
+ if (m_section.get() == NULL)
+ return false;
- if (pos != end)
+ if (m_cfi_data_initialized == false)
{
- if (pos->first.Contains(find_range.GetBaseAddress()))
- {
- // Parse and cache the FDE if we already haven't
- if (pos->second.fde_sp.get() == NULL)
- pos->second.fde_sp = ParseFDE(pos->second.fde_offset);
-
- return pos->second.fde_sp.get();
- }
+ m_section->ReadSectionDataFromObjectFile (&m_objfile, m_cfi_data);
+ m_cfi_data_initialized = true;
}
- return NULL;
-}
+ uint32_t length = m_cfi_data.GetU32 (&offset);
+ dw_offset_t cie_offset = m_cfi_data.GetU32 (&offset);
-void
-DWARFCallFrameInfo::Index ()
-{
- if (m_flags.IsClear(eFlagParsedIndex))
- {
- m_flags.Set (eFlagParsedIndex);
- const bool for_eh_frame = IsEHFrame();
- CIE::shared_ptr empty_cie_sp;
- dw_offset_t offset = 0;
- // Parse all of the CIEs first since we will need them to be able to
- // properly parse the FDE addresses due to them possibly having
- // GNU pointer encodings in their augmentations...
- while (m_cfi_data.ValidOffsetForDataOfSize(offset, 8))
- {
- const dw_offset_t curr_offset = offset;
- const uint32_t length = m_cfi_data.GetU32(&offset);
- const dw_offset_t next_offset = offset + length;
- const dw_offset_t cie_id = m_cfi_data.GetU32(&offset);
+ assert (cie_offset != 0 && cie_offset != UINT32_MAX);
- bool is_cie = for_eh_frame ? cie_id == 0 : cie_id == UINT32_MAX;
- if (is_cie)
- m_cie_map[curr_offset]= ParseCIE(curr_offset);
+ // Translate the CIE_id from the eh_frame format, which
+ // is relative to the FDE offset, into a __eh_frame section
+ // offset
+ if (m_is_eh_frame)
+ cie_offset = current_entry + 4 - cie_offset;
- offset = next_offset;
- }
+ const CIE *cie = GetCIE (cie_offset);
+ assert (cie != NULL);
- // Now go back through and index all FDEs
- offset = 0;
- const lldb::addr_t pc_rel_addr = m_section->GetFileAddress();
- const lldb::addr_t text_addr = LLDB_INVALID_ADDRESS;
- const lldb::addr_t data_addr = LLDB_INVALID_ADDRESS;
- while (m_cfi_data.ValidOffsetForDataOfSize(offset, 8))
- {
- const dw_offset_t curr_offset = offset;
- const dw_offset_t next_offset = offset + m_cfi_data.GetU32(&offset);
- const dw_offset_t cie_id = m_cfi_data.GetU32(&offset);
+ const dw_offset_t end_offset = current_entry + length + 4;
- bool is_fde = for_eh_frame ? cie_id != 0 : cie_id != UINT32_MAX;
- if (is_fde)
- {
- dw_offset_t cie_offset;
- if (for_eh_frame)
- cie_offset = offset - (cie_id + 4);
- else
- cie_offset = cie_id;
-
- const CIE* cie = GetCIE(cie_offset);
- assert(cie);
- lldb::addr_t addr = m_cfi_data.GetGNUEHPointer(&offset, cie->ptr_encoding, pc_rel_addr, text_addr, data_addr);
- lldb::addr_t length = m_cfi_data.GetGNUEHPointer(&offset, cie->ptr_encoding & DW_EH_PE_MASK_ENCODING, pc_rel_addr, text_addr, data_addr);
- m_fde_map[VMRange(addr, addr + length)] = FDEInfo(curr_offset);
- }
+ const lldb::addr_t pc_rel_addr = m_section->GetFileAddress();
+ const lldb::addr_t text_addr = LLDB_INVALID_ADDRESS;
+ const lldb::addr_t data_addr = LLDB_INVALID_ADDRESS;
+ lldb::addr_t range_base = m_cfi_data.GetGNUEHPointer(&offset, cie->ptr_encoding, pc_rel_addr, text_addr, data_addr);
+ lldb::addr_t range_len = m_cfi_data.GetGNUEHPointer(&offset, cie->ptr_encoding & DW_EH_PE_MASK_ENCODING, pc_rel_addr, text_addr, data_addr);
+ AddressRange range (range_base, m_objfile.GetAddressByteSize(), m_objfile.GetSectionList());
+ range.SetByteSize (range_len);
- offset = next_offset;
- }
+ if (cie->augmentation[0] == 'z')
+ {
+ uint32_t aug_data_len = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ offset += aug_data_len;
}
-}
-
-//----------------------------------------------------------------------
-// Parse instructions for a FDE. The initial instruction for the CIE
-// are parsed first, then the instructions for the FDE are parsed
-//----------------------------------------------------------------------
-void
-DWARFCallFrameInfo::ParseInstructions(const CIE *cie, FDE *fde, dw_offset_t instr_offset, uint32_t instr_length)
-{
- if (cie != NULL && fde == NULL)
- return;
uint32_t reg_num = 0;
int32_t op_offset = 0;
uint32_t tmp_uval32;
uint32_t code_align = cie->code_align;
int32_t data_align = cie->data_align;
- typedef std::list<Row> RowStack;
- RowStack row_stack;
- Row row;
- if (fde->IsValidRowIndex(0))
- row = fde->GetRowAtIndex(0);
+ unwind_plan.SetPlanValidAddressRange (range);
+ UnwindPlan::Row row = cie->initial_row;
+
+ unwind_plan.SetRegisterKind (m_reg_kind);
- dw_offset_t offset = instr_offset;
- const dw_offset_t end_offset = instr_offset + instr_length;
- RegisterLocation reg_location;
+ UnwindPlan::Row::RegisterLocation reg_location;
while (m_cfi_data.ValidOffset(offset) && offset < end_offset)
{
uint8_t inst = m_cfi_data.GetU8(&offset);
@@ -730,7 +397,7 @@ DWARFCallFrameInfo::ParseInstructions(const CIE *cie, FDE *fde, dw_offset_t inst
// value that is computed by taking the current entry's location
// value and adding (delta * code_align). All other
// values in the new row are initially identical to the current row.
- fde->AppendRow(row);
+ unwind_plan.AppendRow(row);
row.SlideOffset(extended_opcode * code_align);
}
break;
@@ -758,9 +425,9 @@ DWARFCallFrameInfo::ParseInstructions(const CIE *cie, FDE *fde, dw_offset_t inst
// We only keep enough register locations around to
// unwind what is in our thread, and these are organized
// by the register index in that state, so we need to convert our
- // GCC register number from the EH frame info, to a registe index
+ // GCC register number from the EH frame info, to a register index
- if (fde->IsValidRowIndex(0) && fde->GetRowAtIndex(0).GetRegisterInfo(reg_num, reg_location))
+ if (unwind_plan.IsValidRowIndex(0) && unwind_plan.GetRowAtIndex(0).GetRegisterInfo(reg_num, reg_location))
row.SetRegisterInfo (reg_num, reg_location);
}
break;
@@ -780,8 +447,8 @@ DWARFCallFrameInfo::ParseInstructions(const CIE *cie, FDE *fde, dw_offset_t inst
// specified address as the location. All other values in the new row
// are initially identical to the current row. The new location value
// should always be greater than the current one.
- fde->AppendRow(row);
- row.SetOffset(m_cfi_data.GetPointer(&offset) - fde->GetAddressRange().GetBaseAddress().GetFileAddress());
+ unwind_plan.AppendRow(row);
+ row.SetOffset(m_cfi_data.GetPointer(&offset) - startaddr.GetFileAddress());
}
break;
@@ -790,7 +457,7 @@ DWARFCallFrameInfo::ParseInstructions(const CIE *cie, FDE *fde, dw_offset_t inst
// takes a single uword argument that represents a constant delta.
// This instruction is identical to DW_CFA_advance_loc except for the
// encoding and size of the delta argument.
- fde->AppendRow(row);
+ unwind_plan.AppendRow(row);
row.SlideOffset (m_cfi_data.GetU8(&offset) * code_align);
}
break;
@@ -800,7 +467,7 @@ DWARFCallFrameInfo::ParseInstructions(const CIE *cie, FDE *fde, dw_offset_t inst
// takes a single uword argument that represents a constant delta.
// This instruction is identical to DW_CFA_advance_loc except for the
// encoding and size of the delta argument.
- fde->AppendRow(row);
+ unwind_plan.AppendRow(row);
row.SlideOffset (m_cfi_data.GetU16(&offset) * code_align);
}
break;
@@ -810,7 +477,7 @@ DWARFCallFrameInfo::ParseInstructions(const CIE *cie, FDE *fde, dw_offset_t inst
// takes a single uword argument that represents a constant delta.
// This instruction is identical to DW_CFA_advance_loc except for the
// encoding and size of the delta argument.
- fde->AppendRow(row);
+ unwind_plan.AppendRow(row);
row.SlideOffset (m_cfi_data.GetU32(&offset) * code_align);
}
break;
@@ -833,7 +500,7 @@ DWARFCallFrameInfo::ParseInstructions(const CIE *cie, FDE *fde, dw_offset_t inst
// number. This instruction is identical to DW_CFA_restore except for
// the encoding and size of the register argument.
reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
- if (fde->IsValidRowIndex(0) && fde->GetRowAtIndex(0).GetRegisterInfo(reg_num, reg_location))
+ if (unwind_plan.IsValidRowIndex(0) && unwind_plan.GetRowAtIndex(0).GetRegisterInfo(reg_num, reg_location))
row.SetRegisterInfo (reg_num, reg_location);
}
break;
@@ -881,7 +548,7 @@ DWARFCallFrameInfo::ParseInstructions(const CIE *cie, FDE *fde, dw_offset_t inst
// the stack and place them in the current row. (This operation is
// useful for compilers that move epilogue code into the body of a
// function.)
- row_stack.push_back(row);
+ unwind_plan.AppendRow (row);
break;
case DW_CFA_restore_state : // 0xB
@@ -893,8 +560,7 @@ DWARFCallFrameInfo::ParseInstructions(const CIE *cie, FDE *fde, dw_offset_t inst
// useful for compilers that move epilogue code into the body of a
// function.)
{
- row = row_stack.back();
- row_stack.pop_back();
+ row = unwind_plan.GetRowAtIndex(unwind_plan.GetRowCount() - 1);
}
break;
@@ -1059,285 +725,7 @@ DWARFCallFrameInfo::ParseInstructions(const CIE *cie, FDE *fde, dw_offset_t inst
}
}
}
- fde->AppendRow(row);
-}
+ unwind_plan.AppendRow(row);
-void
-DWARFCallFrameInfo::ParseAll()
-{
- Index();
- fde_map_t::iterator pos, end = m_fde_map.end();
- for (pos = m_fde_map.begin(); pos != end; ++ pos)
- {
- if (pos->second.fde_sp.get() == NULL)
- pos->second.fde_sp = ParseFDE(pos->second.fde_offset);
- }
+ return true;
}
-
-
-//bool
-//DWARFCallFrameInfo::UnwindRegisterAtIndex
-//(
-// const uint32_t reg_idx,
-// const Thread* currState,
-// const DWARFCallFrameInfo::Row* row,
-// mapped_memory_t * memCache,
-// Thread* unwindState
-//)
-//{
-// bool get_reg_success = false;
-//
-// const RegLocation* regLocation = row->regs.GetRegisterInfo(reg_idx);
-//
-// // On some systems, we may not get unwind info for the program counter,
-// // but the return address register can be used to get that information.
-// if (reg_idx == currState->GetPCRegNum(Thread::Index))
-// {
-// const RegLocation* returnAddrRegLocation = row->regs.GetRegisterInfo(currState->GetRARegNum(Thread::Index));
-// if (regLocation == NULL)
-// {
-// // We have nothing to the program counter, so lets see if this
-// // thread state has a return address (link register) that can
-// // help us track down the previous PC
-// regLocation = returnAddrRegLocation;
-// }
-// else if (regLocation->type == RegLocation::unspecified)
-// {
-// // We did have a location that didn't specify a value for unwinding
-// // the PC, so if there is a info for the return return address
-// // register (link register) lets use that
-// if (returnAddrRegLocation)
-// regLocation = returnAddrRegLocation;
-// }
-// }
-//
-// if (regLocation)
-// {
-// mach_vm_address_t unwoundRegValue = INVALID_VMADDR;
-// switch (regLocation->type)
-// {
-// case RegLocation::undefined:
-// // Register is not available, mark it as invalid
-// unwindState->SetRegisterIsValid(reg_idx, Thread::Index, false);
-// return true;
-//
-// case RegLocation::unspecified:
-// // Nothing to do if it is the same
-// return true;
-//
-// case RegLocation::same:
-// // Nothing to do if it is the same
-// return true;
-//
-// case RegLocation::atFPPlusOffset:
-// case RegLocation::isFPPlusOffset:
-// {
-// uint64_t unwindAddress = currState->GetRegisterValue(row->cfa_register, Thread::GCC, INVALID_VMADDR, &get_reg_success);
-//
-// if (get_reg_success)
-// {
-// unwindAddress += row->cfa_offset + regLocation->location.offset;
-//
-// if (regLocation->type == RegLocation::isFPPlusOffset)
-// {
-// unwindState->SetRegisterValue(reg_idx, Thread::Index, unwindAddress);
-// return true;
-// }
-// else
-// {
-// kern_return_t err = mapped_memory_read_pointer(memCache, unwindAddress, &unwoundRegValue);
-// if (err != KERN_SUCCESS)
-// {
-// unwindState->SetRegisterIsValid(reg_idx, Thread::Index, false);
-// return false;
-// }
-// unwindState->SetRegisterValue(reg_idx, Thread::Index, unwoundRegValue);
-// return true;
-// }
-// }
-// else
-// {
-// unwindState->SetRegisterIsValid(reg_idx, Thread::Index, false);
-// }
-// return false;
-// }
-// break;
-//
-// case RegLocation::atDWARFExpression:
-// case RegLocation::isDWARFExpression:
-// {
-// bool swap = false;
-// DWARFExpressionBaton baton = { currState, memCache, swap };
-// uint64_t expr_result = 0;
-// CSBinaryDataRef opcodes(regLocation->location.expr.opcodes, regLocation->location.expr.length, swap);
-// opcodes.SetPointerSize(currState->Is64Bit() ? 8 : 4);
-// const char * expr_err = CSDWARFExpression::Evaluate(DWARFExpressionReadMemoryDCScriptInterpreter::Type,
-// DWARFExpressionReadRegisterDCScriptInterpreter::Type,
-// &baton,
-// opcodes,
-// 0,
-// regLocation->location.expr.length,
-// NULL,
-// expr_result);
-// if (expr_err == NULL)
-// {
-// // SUCCESS!
-// if (regLocation->type == RegLocation::isDWARFExpression)
-// {
-// unwindState->SetRegisterValue(reg_idx, Thread::Index, expr_result);
-// return true;
-// }
-// else
-// {
-// kern_return_t err = mapped_memory_read_pointer(memCache, expr_result, &unwoundRegValue);
-// if (err != KERN_SUCCESS)
-// {
-// unwindState->SetRegisterIsValid(reg_idx, Thread::Index, false);
-// return false;
-// }
-// unwindState->SetRegisterValue(reg_idx, Thread::Index, unwoundRegValue);
-// return true;
-// }
-// }
-// else
-// {
-// // FAIL
-// unwindState->SetRegisterIsValid(reg_idx, Thread::Index, false);
-// }
-// return false;
-// }
-// break;
-//
-//
-// case RegLocation::inRegister:
-// // The value is in another register.
-// unwoundRegValue = currState->GetRegisterValue(regLocation->location.reg, Thread::GCC, 0, &get_reg_success);
-// if (get_reg_success)
-// {
-// unwindState->SetRegisterValue(reg_idx, Thread::Index, unwoundRegValue);
-// return true;
-// }
-// return false;
-//
-// default:
-// break;
-// }
-// }
-//
-// if (reg_idx == currState->GetSPRegNum(Thread::Index))
-// {
-// uint64_t cfa = currState->GetRegisterValue(row->cfa_register, Thread::GCC, 0, &get_reg_success);
-// if (get_reg_success)
-// {
-// return unwindState->SetSP(cfa + row->cfa_offset);
-// }
-// else
-// {
-// unwindState->SetRegisterIsValid(reg_idx, Thread::Index, false);
-// return false;
-// }
-// }
-//
-// return false;
-//}
-
-void
-DWARFCallFrameInfo::Dump(Stream *s, Thread *thread) const
-{
- s->Indent();
- s->Printf("DWARFCallFrameInfo for ");
- *s << m_objfile->GetFileSpec();
- if (m_flags.IsSet(eFlagParsedIndex))
- {
- s->Printf(" (CIE[%zu], FDE[%zu])\n", m_cie_map.size(), m_fde_map.size());
- s->IndentMore();
- cie_map_t::const_iterator cie_pos, cie_end = m_cie_map.end();
- const ArchSpec *arch = &m_objfile->GetModule()->GetArchitecture();
-
- for (cie_pos = m_cie_map.begin(); cie_pos != cie_end; ++ cie_pos)
- {
- if (cie_pos->second.get() == NULL)
- {
- s->Indent();
- s->Printf("CIE{0x%8.8x} - unparsed\n", cie_pos->first);
- }
- else
- {
- cie_pos->second->Dump(s, thread, arch, m_reg_kind);
- }
- }
-
- fde_map_t::const_iterator fde_pos, fde_end = m_fde_map.end();
- for (fde_pos = m_fde_map.begin(); fde_pos != fde_end; ++ fde_pos)
- {
- if (fde_pos->second.fde_sp.get() == NULL)
- {
- s->Indent();
- s->Printf("FDE{0x%8.8x} - unparsed\n", fde_pos->second.fde_offset);
- }
- else
- {
- fde_pos->second.fde_sp->Dump(s, *this, thread);
- }
- }
- s->IndentLess();
- }
- else
- {
- s->PutCString(" (not indexed yet)\n");
- }
-}
-
-
-//uint32_t
-//DWARFCallFrameInfo::UnwindThreadState(const Thread* currState, mapped_memory_t *memCache, bool is_first_frame, Thread* unwindState)
-//{
-// if (currState == NULL || unwindState == NULL)
-// return 0;
-//
-// *unwindState = *currState;
-// uint32_t numRegisterUnwound = 0;
-// uint64_t currPC = currState->GetPC(INVALID_VMADDR);
-//
-// if (currPC != INVALID_VMADDR)
-// {
-// // If this is not the first frame, we care about the previous instruction
-// // since it will be at the instruction following the instruction that
-// // made the function call.
-// uint64_t unwindPC = currPC;
-// if (unwindPC > 0 && !is_first_frame)
-// --unwindPC;
-//
-//#if defined(__i386__) || defined(__x86_64__)
-// // Only on i386 do we have __IMPORT segments that contain trampolines
-// if (!currState->Is64Bit() && ImportRangesContainsAddress(unwindPC))
-// {
-// uint64_t curr_sp = currState->GetSP(INVALID_VMADDR);
-// mach_vm_address_t pc = INVALID_VMADDR;
-// unwindState->SetSP(curr_sp + 4);
-// kern_return_t err = mapped_memory_read_pointer(memCache, curr_sp, &pc);
-// if (err == KERN_SUCCESS)
-// {
-// unwindState->SetPC(pc);
-// return 2;
-// }
-// }
-//#endif
-// FDE *fde = FindFDE(unwindPC);
-// if (fde)
-// {
-// FindRowUserData rowUserData (currState, unwindPC);
-// ParseInstructions (currState, fde, FindRowForAddress, &rowUserData);
-//
-// const uint32_t numRegs = currState->NumRegisters();
-// for (uint32_t regNum = 0; regNum < numRegs; regNum++)
-// {
-// if (UnwindRegisterAtIndex(regNum, currState, &rowUserData.state, memCache, unwindState))
-// numRegisterUnwound++;
-// }
-// }
-// }
-// return numRegisterUnwound;
-//}
-
-
diff --git a/lldb/source/Symbol/FuncUnwinders.cpp b/lldb/source/Symbol/FuncUnwinders.cpp
new file mode 100644
index 00000000000..7998cf14eff
--- /dev/null
+++ b/lldb/source/Symbol/FuncUnwinders.cpp
@@ -0,0 +1,126 @@
+//===-- 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/lldb-private.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Symbol/UnwindTable.h"
+#include "lldb/Utility/UnwindAssemblyProfiler.h"
+#include "lldb/Utility/ArchDefaultUnwindPlan.h"
+#include "lldb/Symbol/DWARFCallFrameInfo.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+FuncUnwinders::FuncUnwinders (UnwindTable& unwind_table, UnwindAssemblyProfiler *assembly_profiler, AddressRange range) :
+ m_unwind_table(unwind_table),
+ m_assembly_profiler(assembly_profiler),
+ m_range(range),
+ m_unwind_at_call_site(NULL),
+ m_unwind_at_non_call_site(NULL),
+ m_fast_unwind(NULL),
+ m_arch_default_unwind(NULL),
+ m_first_non_prologue_insn() { }
+
+FuncUnwinders::~FuncUnwinders ()
+{
+ if (m_unwind_at_call_site)
+ delete m_unwind_at_call_site;
+ if (m_unwind_at_non_call_site)
+ delete m_unwind_at_non_call_site;
+ if (m_fast_unwind)
+ delete m_fast_unwind;
+ if (m_arch_default_unwind)
+ delete m_arch_default_unwind;
+}
+
+UnwindPlan*
+FuncUnwinders::GetUnwindPlanAtCallSite ()
+{
+ if (m_unwind_at_call_site != NULL)
+ return m_unwind_at_call_site;
+ if (!m_range.GetBaseAddress().IsValid())
+ return NULL;
+
+ DWARFCallFrameInfo *eh_frame = m_unwind_table.GetEHFrameInfo();
+ if (eh_frame)
+ {
+ UnwindPlan *up = new UnwindPlan;
+ if (eh_frame->GetUnwindPlan (m_range.GetBaseAddress (), *up) == true)
+ {
+ m_unwind_at_call_site = up;
+ return m_unwind_at_call_site;
+ }
+ }
+ return NULL;
+}
+
+UnwindPlan*
+FuncUnwinders::GetUnwindPlanAtNonCallSite (Thread& thread)
+{
+ if (m_unwind_at_non_call_site != NULL)
+ m_unwind_at_non_call_site;
+ m_unwind_at_non_call_site = new UnwindPlan;
+ m_assembly_profiler->GetNonCallSiteUnwindPlanFromAssembly (m_range, thread, *m_unwind_at_non_call_site);
+ return m_unwind_at_non_call_site;
+}
+
+UnwindPlan*
+FuncUnwinders::GetUnwindPlanFastUnwind (Thread& thread)
+{
+ if (m_fast_unwind != NULL)
+ return m_fast_unwind;
+ m_fast_unwind = new UnwindPlan;
+ m_assembly_profiler->GetFastUnwindPlan (m_range, thread, *m_fast_unwind);
+ return m_fast_unwind;
+}
+
+UnwindPlan*
+FuncUnwinders::GetUnwindPlanArchitectureDefault (Thread& thread)
+{
+ if (m_arch_default_unwind != NULL)
+ return m_arch_default_unwind;
+
+ Address current_pc;
+ Target *target = thread.CalculateTarget();
+ ArchSpec arch;
+ if (target)
+ {
+ ArchSpec arch = target->GetArchitecture ();
+ ArchDefaultUnwindPlan *arch_default = ArchDefaultUnwindPlan::FindPlugin (arch);
+ if (arch_default)
+ {
+ m_arch_default_unwind = arch_default->GetArchDefaultUnwindPlan (thread, current_pc);
+ }
+ }
+
+ return m_arch_default_unwind;
+}
+
+Address&
+FuncUnwinders::GetFirstNonPrologueInsn (Target& target)
+{
+ if (m_first_non_prologue_insn.IsValid())
+ return m_first_non_prologue_insn;
+ m_assembly_profiler->FirstNonPrologueInsn (m_range, target, NULL, m_first_non_prologue_insn);
+ return m_first_non_prologue_insn;
+}
+
+const Address&
+FuncUnwinders::GetFunctionStartAddress () const
+{
+ return m_range.GetBaseAddress();
+}
+
diff --git a/lldb/source/Symbol/UnwindPlan.cpp b/lldb/source/Symbol/UnwindPlan.cpp
new file mode 100644
index 00000000000..45857d67432
--- /dev/null
+++ b/lldb/source/Symbol/UnwindPlan.cpp
@@ -0,0 +1,309 @@
+//===-- UnwindPlan.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/UnwindPlan.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/RegisterContext.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool
+UnwindPlan::Row::RegisterLocation::operator == (const UnwindPlan::Row::RegisterLocation& rhs) const
+{
+ if (m_type != rhs.m_type)
+ return false;
+ if (m_type == atCFAPlusOffset || m_type == isCFAPlusOffset)
+ return m_location.offset == rhs.m_location.offset;
+ if (m_type == inOtherRegister)
+ return m_location.reg_num == rhs.m_location.reg_num;
+ if (m_type == atDWARFExpression || m_type == isDWARFExpression)
+ if (m_location.expr.length == rhs.m_location.expr.length)
+ return !memcmp (m_location.expr.opcodes, rhs.m_location.expr.opcodes, m_location.expr.length);
+ return false;
+}
+
+// This function doesn't copy the dwarf expression bytes; they must remain in allocated
+// memory for the lifespan of this UnwindPlan object.
+void
+UnwindPlan::Row::RegisterLocation::SetAtDWARFExpression (const uint8_t *opcodes, uint32_t len)
+{
+ m_type = atDWARFExpression;
+ m_location.expr.opcodes = opcodes;
+ m_location.expr.length = len;
+}
+
+// This function doesn't copy the dwarf expression bytes; they must remain in allocated
+// memory for the lifespan of this UnwindPlan object.
+void
+UnwindPlan::Row::RegisterLocation::SetIsDWARFExpression (const uint8_t *opcodes, uint32_t len)
+{
+ m_type = isDWARFExpression;
+ m_location.expr.opcodes = opcodes;
+ m_location.expr.length = len;
+}
+
+void
+UnwindPlan::Row::RegisterLocation::SetUnspecified ()
+{
+ m_type = unspecified;
+}
+
+void
+UnwindPlan::Row::RegisterLocation::SetUndefined ()
+{
+ m_type = isUndefined;
+}
+
+void
+UnwindPlan::Row::RegisterLocation::SetSame ()
+{
+ m_type = isSame;
+}
+
+
+void
+UnwindPlan::Row::RegisterLocation::SetAtCFAPlusOffset (int32_t offset)
+{
+ m_type = atCFAPlusOffset;
+ m_location.offset = offset;
+}
+
+void
+UnwindPlan::Row::RegisterLocation::SetIsCFAPlusOffset (int32_t offset)
+{
+ m_type = isCFAPlusOffset;
+ m_location.offset = offset;
+}
+
+void
+UnwindPlan::Row::RegisterLocation::SetInRegister (uint32_t reg_num)
+{
+ m_type = inOtherRegister;
+ m_location.reg_num = reg_num;
+}
+
+void
+UnwindPlan::Row::RegisterLocation::Dump (Stream &s) const
+{
+ switch (m_type)
+ {
+ case unspecified:
+ s.Printf ("unspecified");
+ break;
+ case isUndefined:
+ s.Printf ("isUndefined");
+ break;
+ case isSame:
+ s.Printf ("isSame");
+ break;
+ case atCFAPlusOffset:
+ s.Printf ("atCFAPlusOffset %d", m_location.offset);
+ break;
+ case isCFAPlusOffset:
+ s.Printf ("isCFAPlusOffset %d", m_location.offset);
+ break;
+ case inOtherRegister:
+ s.Printf ("inOtherRegister %d", m_location.reg_num);
+ break;
+ case atDWARFExpression:
+ s.Printf ("atDWARFExpression");
+ break;
+ case isDWARFExpression:
+ s.Printf ("isDWARFExpression");
+ break;
+ }
+}
+
+void
+UnwindPlan::Row::Clear ()
+{
+ m_offset = 0;
+ m_cfa_reg_num = 0;
+ m_cfa_offset = 0;
+ m_register_locations.clear();
+}
+
+void
+UnwindPlan::Row::Dump (Stream& s, int register_kind, Thread* thread) const
+{
+ RegisterContext *rctx = NULL;
+ const RegisterInfo *rinfo = NULL;
+ int translated_regnum;
+ if (thread && thread->GetRegisterContext())
+ {
+ rctx = thread->GetRegisterContext();
+ }
+ s.Printf ("offset %ld, CFA reg ", (long) GetOffset());
+ if (rctx
+ && (translated_regnum = rctx->ConvertRegisterKindToRegisterNumber (register_kind, GetCFARegister())) != -1
+ && (rinfo = rctx->GetRegisterInfoAtIndex (translated_regnum)) != NULL
+ && rinfo->name != NULL
+ && rinfo->name[0] != '\0')
+ {
+ s.Printf ("%s, ", rinfo->name);
+ }
+ else
+ {
+ s.Printf ("%d, ", (int)(int) GetCFARegister());
+ }
+ s.Printf ("CFA offset %d", (int) GetCFAOffset ());
+ for (collection::const_iterator idx = m_register_locations.begin (); idx != m_register_locations.end (); ++idx)
+ {
+ s.Printf (" [");
+ bool printed_name = false;
+ if (thread && thread->GetRegisterContext())
+ {
+ rctx = thread->GetRegisterContext();
+ translated_regnum = rctx->ConvertRegisterKindToRegisterNumber (register_kind, idx->first);
+ rinfo = rctx->GetRegisterInfoAtIndex (translated_regnum);
+ if (rinfo && rinfo->name)
+ {
+ s.Printf ("%s ", rinfo->name);
+ printed_name = true;
+ }
+ }
+ if (!printed_name)
+ {
+ s.Printf ("reg %d ", idx->first);
+ }
+ idx->second.Dump(s);
+ s.Printf ("]");
+ }
+ s.Printf ("\n");
+}
+
+UnwindPlan::Row::Row() :
+ m_offset(0),
+ m_cfa_reg_num(0),
+ m_cfa_offset(0),
+ m_register_locations()
+{
+}
+
+bool
+UnwindPlan::Row::GetRegisterInfo (uint32_t reg_num, UnwindPlan::Row::RegisterLocation& register_location) const
+{
+ collection::const_iterator pos = m_register_locations.find(reg_num);
+ if (pos != m_register_locations.end())
+ {
+ register_location = pos->second;
+ return true;
+ }
+ return false;
+}
+
+void
+UnwindPlan::Row::SetRegisterInfo (uint32_t reg_num, const UnwindPlan::Row::RegisterLocation register_location)
+{
+ m_register_locations[reg_num] = register_location;
+}
+
+
+void
+UnwindPlan::AppendRow (const UnwindPlan::Row &row)
+{
+ if (m_row_list.empty() || m_row_list.back().GetOffset() != row.GetOffset())
+ m_row_list.push_back(row);
+ else
+ m_row_list.back() = row;
+}
+
+const UnwindPlan::Row *
+UnwindPlan::GetRowForFunctionOffset (int offset) const
+{
+ const UnwindPlan::Row *rowp = NULL;
+ for (int i = 0; i < m_row_list.size(); ++i)
+ {
+ if (m_row_list[i].GetOffset() <= offset)
+ {
+ rowp = &m_row_list[i];
+ }
+ else
+ {
+ break;
+ }
+ }
+ return rowp;
+}
+
+bool
+UnwindPlan::IsValidRowIndex (uint32_t idx) const
+{
+ return idx < m_row_list.size();
+}
+
+const UnwindPlan::Row&
+UnwindPlan::GetRowAtIndex (uint32_t idx) const
+{
+ // You must call IsValidRowIndex(idx) first before calling this!!!
+ return m_row_list[idx];
+}
+
+int
+UnwindPlan::GetRowCount () const
+{
+ return m_row_list.size ();
+}
+
+void
+UnwindPlan::SetRegisterKind (uint32_t rk)
+{
+ m_register_kind = rk;
+}
+
+uint32_t
+UnwindPlan::GetRegisterKind (void) const
+{
+ return m_register_kind;
+}
+
+void
+UnwindPlan::SetPlanValidAddressRange (const AddressRange& range)
+{
+ m_plan_valid_address_range = range;
+// .GetBaseAddress() = addr;
+// m_plan_valid_address_range.SetByteSize (range.GetByteSize());
+}
+
+bool
+UnwindPlan::PlanValidAtAddress (Address addr)
+{
+ if (!m_plan_valid_address_range.GetBaseAddress().IsValid())
+ return true;
+
+ if (m_plan_valid_address_range.ContainsFileAddress (addr))
+ return true;
+
+ return false;
+}
+
+void
+UnwindPlan::Dump (Stream& s, Process* process, Thread *thread) const
+{
+ s.Printf ("Address range of this UnwindPlan: ");
+ m_plan_valid_address_range.Dump (&s, process, Address::DumpStyleSectionNameOffset);
+ s.Printf ("\n");
+ s.Printf ("UnwindPlan register kind %d", m_register_kind);
+ switch (m_register_kind)
+ {
+ case eRegisterKindGCC: s.Printf (" [eRegisterKindGCC]"); break;
+ case eRegisterKindDWARF: s.Printf (" [eRegisterKindDWARF]"); break;
+ case eRegisterKindGeneric: s.Printf (" [eRegisterKindGeneric]"); break;
+ case eRegisterKindGDB: s.Printf (" [eRegisterKindGDB]"); break;
+ case eRegisterKindLLDB: s.Printf (" [eRegisterKindLLDB]"); break;
+ default: break;
+ }
+ s.Printf ("\n");
+ for (int i = 0; IsValidRowIndex (i); i++)
+ {
+ s.Printf ("UnwindPlan row at index %d: ", i);
+ m_row_list[i].Dump(s, m_register_kind, thread);
+ }
+}
diff --git a/lldb/source/Symbol/UnwindTable.cpp b/lldb/source/Symbol/UnwindTable.cpp
new file mode 100644
index 00000000000..dcab1933375
--- /dev/null
+++ b/lldb/source/Symbol/UnwindTable.cpp
@@ -0,0 +1,132 @@
+//===-- UnwindTable.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/ObjectFile.h"
+
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/Module.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/Utility/UnwindAssemblyProfiler.h"
+#include "lldb/Symbol/DWARFCallFrameInfo.h"
+
+#include "lldb/Symbol/UnwindTable.h"
+#include <stdio.h>
+
+// There is one UnwindTable object per ObjectFile.
+// It contains a list of Unwind objects -- one per function, populated lazily -- for the ObjectFile.
+// Each Unwind object has multiple UnwindPlans for different scenarios.
+
+using namespace lldb;
+using namespace lldb_private;
+
+UnwindTable::UnwindTable (ObjectFile& objfile) : m_object_file(objfile),
+ m_unwinds(),
+ m_initialized(false),
+ m_eh_frame(NULL),
+ m_assembly_profiler(NULL)
+{
+}
+
+// We can't do some of this initialization when the ObjectFile is running its ctor; delay doing it
+// until needed for something.
+
+void
+UnwindTable::initialize ()
+{
+ if (m_initialized)
+ return;
+
+ SectionList* sl = m_object_file.GetSectionList ();
+ if (sl)
+ {
+ SectionSP sect = sl->FindSectionByType (eSectionTypeEHFrame, true);
+ if (sect.get())
+ {
+ m_eh_frame = new DWARFCallFrameInfo(m_object_file, sect, eRegisterKindGCC, true);
+ }
+ }
+
+ ArchSpec arch;
+ ConstString str;
+ m_object_file.GetTargetTriple (str);
+ arch.SetArchFromTargetTriple (str.GetCString());
+ m_assembly_profiler = UnwindAssemblyProfiler::FindPlugin (arch);
+
+ m_initialized = true;
+}
+
+UnwindTable::~UnwindTable ()
+{
+ if (m_eh_frame)
+ delete m_eh_frame;
+}
+
+FuncUnwindersSP
+UnwindTable::GetFuncUnwindersContainingAddress (const Address& addr, SymbolContext &sc)
+{
+ FuncUnwindersSP no_unwind_found;
+
+ initialize();
+
+ // Create a FuncUnwinders object for the binary search below
+ AddressRange search_range(addr, 1);
+ FuncUnwindersSP search_unwind(new FuncUnwinders (*this, NULL, search_range));
+
+ const_iterator idx;
+ idx = std::lower_bound (m_unwinds.begin(), m_unwinds.end(), search_unwind);
+
+ bool found_match = true;
+ if (m_unwinds.size() == 0)
+ {
+ found_match = false;
+ }
+ else if (idx == m_unwinds.end())
+ {
+ --idx;
+ }
+ if (idx != m_unwinds.begin() && (*idx)->GetFunctionStartAddress().GetOffset() != addr.GetOffset())
+ {
+ --idx;
+ }
+ if (found_match && (*idx)->ContainsAddress (addr))
+ {
+ return *idx;
+ }
+
+ AddressRange range;
+ if (sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, range))
+ {
+ FuncUnwindersSP unw(new FuncUnwinders(*this, m_assembly_profiler, range));
+ m_unwinds.push_back (unw);
+ std::sort (m_unwinds.begin(), m_unwinds.end());
+ return unw;
+ }
+ else
+ {
+ // Does the eh_frame unwind info has a function bounds defined for this addr?
+ if (m_eh_frame->GetAddressRange (addr, range))
+ {
+ FuncUnwindersSP unw(new FuncUnwinders(*this, m_assembly_profiler, range));
+ m_unwinds.push_back (unw);
+ std::sort (m_unwinds.begin(), m_unwinds.end());
+ return unw;
+ // FIXME we should create a syntheic Symbol based on the address range with a synthesized symbol name
+ }
+ }
+ return no_unwind_found;
+}
+
+DWARFCallFrameInfo *
+UnwindTable::GetEHFrameInfo ()
+{
+ initialize();
+ return m_eh_frame;
+}
OpenPOWER on IntegriCloud