diff options
Diffstat (limited to 'lldb/source/Symbol/UnwindPlan.cpp')
-rw-r--r-- | lldb/source/Symbol/UnwindPlan.cpp | 309 |
1 files changed, 309 insertions, 0 deletions
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); + } +} |