| //===-- 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/Process.h" |
| #include "lldb/Target/RegisterContext.h" |
| #include "lldb/Target/Thread.h" |
| #include "lldb/Core/ConstString.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 *reg_ctx = NULL; |
| const RegisterInfo *rinfo = NULL; |
| int translated_regnum; |
| if (thread && thread->GetRegisterContext()) |
| reg_ctx = thread->GetRegisterContext().get(); |
| |
| s.Printf ("offset %ld, CFA reg ", (long) GetOffset()); |
| if (reg_ctx |
| && (translated_regnum = reg_ctx->ConvertRegisterKindToRegisterNumber (register_kind, GetCFARegister())) != -1 |
| && (rinfo = reg_ctx->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 (reg_ctx) |
| { |
| translated_regnum = reg_ctx->ConvertRegisterKindToRegisterNumber (register_kind, idx->first); |
| rinfo = reg_ctx->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; |
| if (offset == -1 && m_row_list.size() > 0) |
| { |
| return &m_row_list[m_row_list.size() - 1]; |
| } |
| 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) |
| { |
| if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0) |
| { |
| 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() || m_plan_valid_address_range.GetByteSize() == 0) |
| return true; |
| |
| if (!addr.IsValid()) |
| return true; |
| |
| if (m_plan_valid_address_range.ContainsFileAddress (addr)) |
| return true; |
| |
| return false; |
| } |
| |
| void |
| UnwindPlan::Dump (Stream& s, Thread *thread) const |
| { |
| if (!m_source_name.IsEmpty()) |
| { |
| s.Printf ("This UnwindPlan originally sourced from %s\n", m_source_name.GetCString()); |
| } |
| if (m_plan_valid_address_range.GetBaseAddress().IsValid() && m_plan_valid_address_range.GetByteSize() > 0) |
| { |
| s.Printf ("Address range of this UnwindPlan: "); |
| m_plan_valid_address_range.Dump (&s, &thread->GetProcess().GetTarget(), Address::DumpStyleSectionNameOffset); |
| s.Printf ("\n"); |
| } |
| else |
| { |
| s.Printf ("No valid address range recorded for this UnwindPlan.\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); |
| } |
| } |
| |
| void |
| UnwindPlan::SetSourceName (const char *source) |
| { |
| m_source_name = ConstString (source); |
| } |
| |
| ConstString |
| UnwindPlan::GetSourceName () const |
| { |
| return m_source_name; |
| } |