brintos

brintos / llvm-project-archived public Read only

0
0
Text · 18.4 KiB · 9245e52 Raw
589 lines · cpp
1//===-- UnwindPlan.cpp ----------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Symbol/UnwindPlan.h"10 11#include "lldb/Target/Process.h"12#include "lldb/Target/RegisterContext.h"13#include "lldb/Target/Target.h"14#include "lldb/Target/Thread.h"15#include "lldb/Utility/ConstString.h"16#include "lldb/Utility/LLDBLog.h"17#include "lldb/Utility/Log.h"18#include "llvm/ADT/STLExtras.h"19#include "llvm/DebugInfo/DIContext.h"20#include "llvm/DebugInfo/DWARF/DWARFExpressionPrinter.h"21#include "llvm/DebugInfo/DWARF/LowLevel/DWARFExpression.h"22#include <optional>23 24using namespace lldb;25using namespace lldb_private;26 27bool UnwindPlan::Row::AbstractRegisterLocation::operator==(28    const UnwindPlan::Row::AbstractRegisterLocation &rhs) const {29  if (m_type == rhs.m_type) {30    switch (m_type) {31    case unspecified:32    case undefined:33    case same:34      return true;35 36    case atCFAPlusOffset:37    case isCFAPlusOffset:38    case atAFAPlusOffset:39    case isAFAPlusOffset:40      return m_location.offset == rhs.m_location.offset;41 42    case inOtherRegister:43      return m_location.reg_num == rhs.m_location.reg_num;44 45    case atDWARFExpression:46    case isDWARFExpression:47      if (m_location.expr.length == rhs.m_location.expr.length)48        return !memcmp(m_location.expr.opcodes, rhs.m_location.expr.opcodes,49                       m_location.expr.length);50      break;51    case isConstant:52      return m_location.constant_value == rhs.m_location.constant_value;53    }54  }55  return false;56}57 58// This function doesn't copy the dwarf expression bytes; they must remain in59// allocated memory for the lifespan of this UnwindPlan object.60void UnwindPlan::Row::AbstractRegisterLocation::SetAtDWARFExpression(61    const uint8_t *opcodes, uint32_t len) {62  m_type = atDWARFExpression;63  m_location.expr.opcodes = opcodes;64  m_location.expr.length = len;65}66 67// This function doesn't copy the dwarf expression bytes; they must remain in68// allocated memory for the lifespan of this UnwindPlan object.69void UnwindPlan::Row::AbstractRegisterLocation::SetIsDWARFExpression(70    const uint8_t *opcodes, uint32_t len) {71  m_type = isDWARFExpression;72  m_location.expr.opcodes = opcodes;73  m_location.expr.length = len;74}75 76static std::optional<std::pair<lldb::ByteOrder, uint32_t>>77GetByteOrderAndAddrSize(Thread *thread) {78  if (!thread)79    return std::nullopt;80  ProcessSP process_sp = thread->GetProcess();81  if (!process_sp)82    return std::nullopt;83  ArchSpec arch = process_sp->GetTarget().GetArchitecture();84  return std::make_pair(arch.GetByteOrder(), arch.GetAddressByteSize());85}86 87static void DumpDWARFExpr(Stream &s, llvm::ArrayRef<uint8_t> expr, Thread *thread) {88  if (auto order_and_width = GetByteOrderAndAddrSize(thread)) {89    llvm::DataExtractor data(expr, order_and_width->first == eByteOrderLittle,90                             order_and_width->second);91    llvm::DWARFExpression E(data, order_and_width->second,92                            llvm::dwarf::DWARF32);93    printDwarfExpression(&E, s.AsRawOstream(), llvm::DIDumpOptions(), nullptr);94  } else95    s.PutCString("dwarf-expr");96}97 98void UnwindPlan::Row::AbstractRegisterLocation::Dump(99    Stream &s, const UnwindPlan *unwind_plan, const UnwindPlan::Row *row,100    Thread *thread, bool verbose) const {101  switch (m_type) {102  case unspecified:103    if (verbose)104      s.PutCString("=<unspec>");105    else106      s.PutCString("=!");107    break;108  case undefined:109    if (verbose)110      s.PutCString("=<undef>");111    else112      s.PutCString("=?");113    break;114  case same:115    s.PutCString("= <same>");116    break;117 118  case atCFAPlusOffset:119  case isCFAPlusOffset: {120    s.PutChar('=');121    if (m_type == atCFAPlusOffset)122      s.PutChar('[');123    s.Printf("CFA%+d", m_location.offset);124    if (m_type == atCFAPlusOffset)125      s.PutChar(']');126  } break;127 128  case atAFAPlusOffset:129  case isAFAPlusOffset: {130    s.PutChar('=');131    if (m_type == atAFAPlusOffset)132      s.PutChar('[');133    s.Printf("AFA%+d", m_location.offset);134    if (m_type == atAFAPlusOffset)135      s.PutChar(']');136  } break;137 138  case inOtherRegister: {139    const RegisterInfo *other_reg_info = nullptr;140    if (unwind_plan)141      other_reg_info = unwind_plan->GetRegisterInfo(thread, m_location.reg_num);142    if (other_reg_info)143      s.Printf("=%s", other_reg_info->name);144    else145      s.Printf("=reg(%u)", m_location.reg_num);146  } break;147 148  case atDWARFExpression:149  case isDWARFExpression: {150    s.PutChar('=');151    if (m_type == atDWARFExpression)152      s.PutChar('[');153    DumpDWARFExpr(154        s, llvm::ArrayRef(m_location.expr.opcodes, m_location.expr.length),155        thread);156    if (m_type == atDWARFExpression)157      s.PutChar(']');158  } break;159  case isConstant:160    s.Printf("=0x%" PRIx64, m_location.constant_value);161    break;162  }163}164 165static void DumpRegisterName(Stream &s, const UnwindPlan *unwind_plan,166                             Thread *thread, uint32_t reg_num) {167  const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo(thread, reg_num);168  if (reg_info)169    s.PutCString(reg_info->name);170  else171    s.Printf("reg(%u)", reg_num);172}173 174bool UnwindPlan::Row::FAValue::175operator==(const UnwindPlan::Row::FAValue &rhs) const {176  if (m_type == rhs.m_type) {177    switch (m_type) {178    case unspecified:179    case isRaSearch:180      return m_value.ra_search_offset == rhs.m_value.ra_search_offset;181 182    case isRegisterPlusOffset:183      return m_value.reg.offset == rhs.m_value.reg.offset;184 185    case isRegisterDereferenced:186      return m_value.reg.reg_num == rhs.m_value.reg.reg_num;187 188    case isDWARFExpression:189      if (m_value.expr.length == rhs.m_value.expr.length)190        return !memcmp(m_value.expr.opcodes, rhs.m_value.expr.opcodes,191                       m_value.expr.length);192      break;193    case isConstant:194      return m_value.constant == rhs.m_value.constant;195    }196  }197  return false;198}199 200void UnwindPlan::Row::FAValue::Dump(Stream &s, const UnwindPlan *unwind_plan,201                                     Thread *thread) const {202  switch (m_type) {203  case isRegisterPlusOffset:204    DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);205    s.Printf("%+3d", m_value.reg.offset);206    break;207  case isRegisterDereferenced:208    s.PutChar('[');209    DumpRegisterName(s, unwind_plan, thread, m_value.reg.reg_num);210    s.PutChar(']');211    break;212  case isDWARFExpression:213    DumpDWARFExpr(s, llvm::ArrayRef(m_value.expr.opcodes, m_value.expr.length),214                  thread);215    break;216  case unspecified:217    s.PutCString("unspecified");218    break;219  case isRaSearch:220    s.Printf("RaSearch@SP%+d", m_value.ra_search_offset);221    break;222  case isConstant:223    s.Printf("0x%" PRIx64, m_value.constant);224  }225}226 227void UnwindPlan::Row::Clear() {228  m_cfa_value.SetUnspecified();229  m_afa_value.SetUnspecified();230  m_offset = 0;231  m_unspecified_registers_are_undefined = false;232  m_register_locations.clear();233}234 235void UnwindPlan::Row::Dump(Stream &s, const UnwindPlan *unwind_plan,236                           Thread *thread, addr_t base_addr) const {237  if (base_addr != LLDB_INVALID_ADDRESS)238    s.Printf("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset());239  else240    s.Printf("%4" PRId64 ": CFA=", GetOffset());241 242  m_cfa_value.Dump(s, unwind_plan, thread);243 244  if (!m_afa_value.IsUnspecified()) {245    s.Printf(" AFA=");246    m_afa_value.Dump(s, unwind_plan, thread);247  }248 249  s.Printf(" => ");250  for (collection::const_iterator idx = m_register_locations.begin();251       idx != m_register_locations.end(); ++idx) {252    DumpRegisterName(s, unwind_plan, thread, idx->first);253    const bool verbose = false;254    idx->second.Dump(s, unwind_plan, this, thread, verbose);255    s.PutChar(' ');256  }257}258 259UnwindPlan::Row::Row() : m_cfa_value(), m_afa_value(), m_register_locations() {}260 261bool UnwindPlan::Row::GetRegisterInfo(262    uint32_t reg_num,263    UnwindPlan::Row::AbstractRegisterLocation &register_location) const {264  collection::const_iterator pos = m_register_locations.find(reg_num);265  if (pos != m_register_locations.end()) {266    register_location = pos->second;267    return true;268  }269  if (m_unspecified_registers_are_undefined) {270    register_location.SetUndefined();271    return true;272  }273  return false;274}275 276void UnwindPlan::Row::RemoveRegisterInfo(uint32_t reg_num) {277  collection::const_iterator pos = m_register_locations.find(reg_num);278  if (pos != m_register_locations.end()) {279    m_register_locations.erase(pos);280  }281}282 283void UnwindPlan::Row::SetRegisterInfo(284    uint32_t reg_num,285    const UnwindPlan::Row::AbstractRegisterLocation register_location) {286  m_register_locations[reg_num] = register_location;287}288 289bool UnwindPlan::Row::SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num,290                                                           int32_t offset,291                                                           bool can_replace) {292  if (!can_replace &&293      m_register_locations.find(reg_num) != m_register_locations.end())294    return false;295  AbstractRegisterLocation reg_loc;296  reg_loc.SetAtCFAPlusOffset(offset);297  m_register_locations[reg_num] = reg_loc;298  return true;299}300 301bool UnwindPlan::Row::SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num,302                                                           int32_t offset,303                                                           bool can_replace) {304  if (!can_replace &&305      m_register_locations.find(reg_num) != m_register_locations.end())306    return false;307  AbstractRegisterLocation reg_loc;308  reg_loc.SetIsCFAPlusOffset(offset);309  m_register_locations[reg_num] = reg_loc;310  return true;311}312 313bool UnwindPlan::Row::SetRegisterLocationToUndefined(314    uint32_t reg_num, bool can_replace, bool can_replace_only_if_unspecified) {315  collection::iterator pos = m_register_locations.find(reg_num);316  collection::iterator end = m_register_locations.end();317 318  if (pos != end) {319    if (!can_replace)320      return false;321    if (can_replace_only_if_unspecified && !pos->second.IsUnspecified())322      return false;323  }324  AbstractRegisterLocation reg_loc;325  reg_loc.SetUndefined();326  m_register_locations[reg_num] = reg_loc;327  return true;328}329 330bool UnwindPlan::Row::SetRegisterLocationToUnspecified(uint32_t reg_num,331                                                       bool can_replace) {332  if (!can_replace &&333      m_register_locations.find(reg_num) != m_register_locations.end())334    return false;335  AbstractRegisterLocation reg_loc;336  reg_loc.SetUnspecified();337  m_register_locations[reg_num] = reg_loc;338  return true;339}340 341bool UnwindPlan::Row::SetRegisterLocationToRegister(uint32_t reg_num,342                                                    uint32_t other_reg_num,343                                                    bool can_replace) {344  if (!can_replace &&345      m_register_locations.find(reg_num) != m_register_locations.end())346    return false;347  AbstractRegisterLocation reg_loc;348  reg_loc.SetInRegister(other_reg_num);349  m_register_locations[reg_num] = reg_loc;350  return true;351}352 353bool UnwindPlan::Row::SetRegisterLocationToSame(uint32_t reg_num,354                                                bool must_replace) {355  if (must_replace &&356      m_register_locations.find(reg_num) == m_register_locations.end())357    return false;358  AbstractRegisterLocation reg_loc;359  reg_loc.SetSame();360  m_register_locations[reg_num] = reg_loc;361  return true;362}363 364bool UnwindPlan::Row::SetRegisterLocationToIsDWARFExpression(365    uint32_t reg_num, const uint8_t *opcodes, uint32_t len, bool can_replace) {366  if (!can_replace &&367      m_register_locations.find(reg_num) != m_register_locations.end())368    return false;369  AbstractRegisterLocation reg_loc;370  reg_loc.SetIsDWARFExpression(opcodes, len);371  m_register_locations[reg_num] = reg_loc;372  return true;373}374 375bool UnwindPlan::Row::SetRegisterLocationToIsConstant(uint32_t reg_num,376                                                      uint64_t constant,377                                                      bool can_replace) {378  if (!can_replace &&379      m_register_locations.find(reg_num) != m_register_locations.end())380    return false;381  AbstractRegisterLocation reg_loc;382  reg_loc.SetIsConstant(constant);383  m_register_locations[reg_num] = reg_loc;384  return true;385}386 387bool UnwindPlan::Row::operator==(const UnwindPlan::Row &rhs) const {388  return m_offset == rhs.m_offset && m_cfa_value == rhs.m_cfa_value &&389         m_afa_value == rhs.m_afa_value &&390         m_unspecified_registers_are_undefined ==391             rhs.m_unspecified_registers_are_undefined &&392         m_register_locations == rhs.m_register_locations;393}394 395void UnwindPlan::AppendRow(Row row) {396  if (m_row_list.empty() || m_row_list.back().GetOffset() != row.GetOffset())397    m_row_list.push_back(std::move(row));398  else399    m_row_list.back() = std::move(row);400}401 402struct RowLess {403  bool operator()(int64_t a, const UnwindPlan::Row &b) const {404    return a < b.GetOffset();405  }406  bool operator()(const UnwindPlan::Row &a, int64_t b) const {407    return a.GetOffset() < b;408  }409};410 411void UnwindPlan::InsertRow(Row row, bool replace_existing) {412  auto it = llvm::lower_bound(m_row_list, row.GetOffset(), RowLess());413  if (it == m_row_list.end() || it->GetOffset() > row.GetOffset())414    m_row_list.insert(it, std::move(row));415  else {416    assert(it->GetOffset() == row.GetOffset());417    if (replace_existing)418      *it = std::move(row);419  }420}421 422const UnwindPlan::Row *423UnwindPlan::GetRowForFunctionOffset(std::optional<int64_t> offset) const {424  auto it = offset ? llvm::upper_bound(m_row_list, *offset, RowLess())425                   : m_row_list.end();426  if (it == m_row_list.begin())427    return nullptr;428  // upper_bound returns the row strictly greater than our desired offset, which429  // means that the row before it is a match.430  return &*std::prev(it);431}432 433bool UnwindPlan::IsValidRowIndex(uint32_t idx) const {434  return idx < m_row_list.size();435}436 437const UnwindPlan::Row *UnwindPlan::GetRowAtIndex(uint32_t idx) const {438  if (idx < m_row_list.size())439    return &m_row_list[idx];440  LLDB_LOG(GetLog(LLDBLog::Unwind),441           "error: UnwindPlan::GetRowAtIndex(idx = {0}) invalid index "442           "(number rows is {1})",443           idx, m_row_list.size());444  return nullptr;445}446 447const UnwindPlan::Row *UnwindPlan::GetLastRow() const {448  if (m_row_list.empty()) {449    LLDB_LOG(GetLog(LLDBLog::Unwind),450             "UnwindPlan::GetLastRow() when rows are empty");451    return nullptr;452  }453  return &m_row_list.back();454}455 456bool UnwindPlan::PlanValidAtAddress(Address addr) const {457  // If this UnwindPlan has no rows, it is an invalid UnwindPlan.458  if (GetRowCount() == 0) {459    Log *log = GetLog(LLDBLog::Unwind);460    if (log) {461      StreamString s;462      if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) {463        LLDB_LOGF(log,464                  "UnwindPlan is invalid -- no unwind rows for UnwindPlan "465                  "'%s' at address %s",466                  m_source_name.GetCString(), s.GetData());467      } else {468        LLDB_LOGF(log,469                  "UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s'",470                  m_source_name.GetCString());471      }472    }473    return false;474  }475 476  // If the 0th Row of unwind instructions is missing, or if it doesn't provide477  // a register to use to find the Canonical Frame Address, this is not a valid478  // UnwindPlan.479  const Row *row0 = GetRowAtIndex(0);480  if (!row0 ||481      row0->GetCFAValue().GetValueType() == Row::FAValue::unspecified) {482    Log *log = GetLog(LLDBLog::Unwind);483    if (log) {484      StreamString s;485      if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) {486        LLDB_LOGF(log,487                  "UnwindPlan is invalid -- no CFA register defined in row 0 "488                  "for UnwindPlan '%s' at address %s",489                  m_source_name.GetCString(), s.GetData());490      } else {491        LLDB_LOGF(log,492                  "UnwindPlan is invalid -- no CFA register defined in row 0 "493                  "for UnwindPlan '%s'",494                  m_source_name.GetCString());495      }496    }497    return false;498  }499 500  if (m_plan_valid_ranges.empty())501    return true;502 503  if (!addr.IsValid())504    return true;505 506  return llvm::any_of(m_plan_valid_ranges, [&](const AddressRange &range) {507    return range.ContainsFileAddress(addr);508  });509}510 511void UnwindPlan::Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const {512  if (!m_source_name.IsEmpty()) {513    s.Printf("This UnwindPlan originally sourced from %s\n",514             m_source_name.GetCString());515  }516  s.Printf("This UnwindPlan is sourced from the compiler: ");517  switch (m_plan_is_sourced_from_compiler) {518  case eLazyBoolYes:519    s.Printf("yes.\n");520    break;521  case eLazyBoolNo:522    s.Printf("no.\n");523    break;524  case eLazyBoolCalculate:525    s.Printf("not specified.\n");526    break;527  }528  s.Printf("This UnwindPlan is valid at all instruction locations: ");529  switch (m_plan_is_valid_at_all_instruction_locations) {530  case eLazyBoolYes:531    s.Printf("yes.\n");532    break;533  case eLazyBoolNo:534    s.Printf("no.\n");535    break;536  case eLazyBoolCalculate:537    s.Printf("not specified.\n");538    break;539  }540  s.Printf("This UnwindPlan is for a trap handler function: ");541  switch (m_plan_is_for_signal_trap) {542  case eLazyBoolYes:543    s.Printf("yes.\n");544    break;545  case eLazyBoolNo:546    s.Printf("no.\n");547    break;548  case eLazyBoolCalculate:549    s.Printf("not specified.\n");550    break;551  }552  if (!m_plan_valid_ranges.empty()) {553    s.PutCString("Address range of this UnwindPlan: ");554    TargetSP target_sp(thread->CalculateTarget());555    for (const AddressRange &range : m_plan_valid_ranges)556      range.Dump(&s, target_sp.get(), Address::DumpStyleSectionNameOffset);557    s.EOL();558  }559  for (const auto &[index, row] : llvm::enumerate(m_row_list)) {560    s.Format("row[{0}]: ", index);561    row.Dump(s, this, thread, base_addr);562    s << "\n";563  }564}565 566void UnwindPlan::SetSourceName(const char *source) {567  m_source_name = ConstString(source);568}569 570ConstString UnwindPlan::GetSourceName() const { return m_source_name; }571 572const RegisterInfo *UnwindPlan::GetRegisterInfo(Thread *thread,573                                                uint32_t unwind_reg) const {574  if (thread) {575    RegisterContext *reg_ctx = thread->GetRegisterContext().get();576    if (reg_ctx) {577      uint32_t reg;578      if (m_register_kind == eRegisterKindLLDB)579        reg = unwind_reg;580      else581        reg = reg_ctx->ConvertRegisterKindToRegisterNumber(m_register_kind,582                                                           unwind_reg);583      if (reg != LLDB_INVALID_REGNUM)584        return reg_ctx->GetRegisterInfoAtIndex(reg);585    }586  }587  return nullptr;588}589