brintos

brintos / llvm-project-archived public Read only

0
0
Text · 23.6 KiB · af32e0e Raw
727 lines · cpp
1//===-- Variable.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/Variable.h"10 11#include "lldb/Core/Module.h"12#include "lldb/Symbol/Block.h"13#include "lldb/Symbol/CompileUnit.h"14#include "lldb/Symbol/CompilerDecl.h"15#include "lldb/Symbol/CompilerDeclContext.h"16#include "lldb/Symbol/Function.h"17#include "lldb/Symbol/SymbolContext.h"18#include "lldb/Symbol/SymbolFile.h"19#include "lldb/Symbol/Type.h"20#include "lldb/Symbol/TypeSystem.h"21#include "lldb/Symbol/VariableList.h"22#include "lldb/Target/ABI.h"23#include "lldb/Target/Process.h"24#include "lldb/Target/RegisterContext.h"25#include "lldb/Target/StackFrame.h"26#include "lldb/Target/Target.h"27#include "lldb/Target/Thread.h"28#include "lldb/Utility/LLDBLog.h"29#include "lldb/Utility/Log.h"30#include "lldb/Utility/RegularExpression.h"31#include "lldb/Utility/Stream.h"32#include "lldb/ValueObject/ValueObject.h"33#include "lldb/ValueObject/ValueObjectVariable.h"34 35#include "llvm/ADT/Twine.h"36 37using namespace lldb;38using namespace lldb_private;39 40Variable::Variable(lldb::user_id_t uid, const char *name, const char *mangled,41                   const lldb::SymbolFileTypeSP &symfile_type_sp,42                   ValueType scope, SymbolContextScope *context,43                   const RangeList &scope_range, Declaration *decl_ptr,44                   const DWARFExpressionList &location_list, bool external,45                   bool artificial, bool location_is_constant_data,46                   bool static_member)47    : UserID(uid), m_name(name), m_mangled(ConstString(mangled)),48      m_symfile_type_sp(symfile_type_sp), m_scope(scope),49      m_owner_scope(context), m_scope_range(scope_range),50      m_declaration(decl_ptr), m_location_list(location_list), m_external(external),51      m_artificial(artificial), m_loc_is_const_data(location_is_constant_data),52      m_static_member(static_member) {}53 54Variable::~Variable() = default;55 56lldb::LanguageType Variable::GetLanguage() const {57  lldb::LanguageType lang = m_mangled.GuessLanguage();58  if (lang != lldb::eLanguageTypeUnknown)59    return lang;60 61  if (auto *func = m_owner_scope->CalculateSymbolContextFunction()) {62    if ((lang = func->GetLanguage()) != lldb::eLanguageTypeUnknown)63      return lang;64  } else if (auto *comp_unit =65                 m_owner_scope->CalculateSymbolContextCompileUnit()) {66    if ((lang = comp_unit->GetLanguage()) != lldb::eLanguageTypeUnknown)67      return lang;68  }69 70  return lldb::eLanguageTypeUnknown;71}72 73ConstString Variable::GetName() const {74  ConstString name = m_mangled.GetName();75  if (name)76    return name;77  return m_name;78}79 80ConstString Variable::GetUnqualifiedName() const { return m_name; }81 82bool Variable::NameMatches(ConstString name) const {83  if (m_name == name)84    return true;85  SymbolContext variable_sc;86  m_owner_scope->CalculateSymbolContext(&variable_sc);87 88  return m_mangled.NameMatches(name);89}90bool Variable::NameMatches(const RegularExpression &regex) const {91  if (regex.Execute(m_name.AsCString()))92    return true;93  if (m_mangled)94    return m_mangled.NameMatches(regex);95  return false;96}97 98Type *Variable::GetType() {99  if (m_symfile_type_sp)100    return m_symfile_type_sp->GetType();101  return nullptr;102}103 104void Variable::Dump(Stream *s, bool show_context) const {105  s->Printf("%p: ", static_cast<const void *>(this));106  s->Indent();107  *s << "Variable" << (const UserID &)*this;108 109  if (m_name)110    *s << ", name = \"" << m_name << "\"";111 112  if (m_symfile_type_sp) {113    Type *type = m_symfile_type_sp->GetType();114    if (type) {115      s->Format(", type = {{{0:x-16}} {1} (", type->GetID(), type);116      type->DumpTypeName(s);117      s->PutChar(')');118    }119  }120 121  if (m_scope != eValueTypeInvalid) {122    s->PutCString(", scope = ");123    switch (m_scope) {124    case eValueTypeVariableGlobal:125      s->PutCString(m_external ? "global" : "static");126      break;127    case eValueTypeVariableArgument:128      s->PutCString("parameter");129      break;130    case eValueTypeVariableLocal:131      s->PutCString("local");132      break;133    case eValueTypeVariableThreadLocal:134      s->PutCString("thread local");135      break;136    default:137      s->AsRawOstream() << "??? (" << m_scope << ')';138    }139  }140 141  if (show_context && m_owner_scope != nullptr) {142    s->PutCString(", context = ( ");143    m_owner_scope->DumpSymbolContext(s);144    s->PutCString(" )");145  }146 147  bool show_fullpaths = false;148  m_declaration.Dump(s, show_fullpaths);149 150  if (m_location_list.IsValid()) {151    s->PutCString(", location = ");152    ABISP abi;153    if (m_owner_scope) {154      ModuleSP module_sp(m_owner_scope->CalculateSymbolContextModule());155      if (module_sp)156        abi = ABI::FindPlugin(ProcessSP(), module_sp->GetArchitecture());157    }158    m_location_list.GetDescription(s, lldb::eDescriptionLevelBrief, abi.get());159  }160 161  if (m_external)162    s->PutCString(", external");163 164  if (m_artificial)165    s->PutCString(", artificial");166 167  s->EOL();168}169 170bool Variable::DumpDeclaration(Stream *s, bool show_fullpaths,171                               bool show_module) {172  bool dumped_declaration_info = false;173  if (m_owner_scope) {174    SymbolContext sc;175    m_owner_scope->CalculateSymbolContext(&sc);176    sc.block = nullptr;177    sc.line_entry.Clear();178    bool show_inlined_frames = false;179    const bool show_function_arguments = true;180    const bool show_function_name = true;181 182    dumped_declaration_info = sc.DumpStopContext(183        s, nullptr, Address(), show_fullpaths, show_module, show_inlined_frames,184        show_function_arguments, show_function_name);185 186    if (sc.function)187      s->PutChar(':');188  }189  if (m_declaration.DumpStopContext(s, false))190    dumped_declaration_info = true;191  return dumped_declaration_info;192}193 194size_t Variable::MemorySize() const { return sizeof(Variable); }195 196CompilerDeclContext Variable::GetDeclContext() {197  Type *type = GetType();198  if (type)199    return type->GetSymbolFile()->GetDeclContextContainingUID(GetID());200  return CompilerDeclContext();201}202 203CompilerDecl Variable::GetDecl() {204  Type *type = GetType();205  return type ? type->GetSymbolFile()->GetDeclForUID(GetID()) : CompilerDecl();206}207 208void Variable::CalculateSymbolContext(SymbolContext *sc) {209  if (m_owner_scope) {210    m_owner_scope->CalculateSymbolContext(sc);211    sc->variable = this;212  } else213    sc->Clear(false);214}215 216bool Variable::LocationIsValidForFrame(StackFrame *frame) {217  if (frame) {218    Function *function =219        frame->GetSymbolContext(eSymbolContextFunction).function;220    if (function) {221      TargetSP target_sp(frame->CalculateTarget());222 223      addr_t loclist_base_load_addr =224          function->GetAddress().GetLoadAddress(target_sp.get());225      if (loclist_base_load_addr == LLDB_INVALID_ADDRESS)226        return false;227      // It is a location list. We just need to tell if the location list228      // contains the current address when converted to a load address229      return m_location_list.ContainsAddress(230          loclist_base_load_addr,231          frame->GetFrameCodeAddressForSymbolication().GetLoadAddress(232              target_sp.get()));233    }234  }235  return false;236}237 238bool Variable::LocationIsValidForAddress(const Address &address) {239  // Be sure to resolve the address to section offset prior to calling this240  // function.241  if (address.IsSectionOffset()) {242    // We need to check if the address is valid for both scope range and value243    // range.244    // Empty scope range means block range.245    bool valid_in_scope_range =246        GetScopeRange().IsEmpty() || GetScopeRange().FindEntryThatContains(247                                         address.GetFileAddress()) != nullptr;248    if (!valid_in_scope_range)249      return false;250    SymbolContext sc;251    CalculateSymbolContext(&sc);252    if (sc.module_sp == address.GetModule()) {253      // Is the variable is described by a single location?254      if (m_location_list.IsAlwaysValidSingleExpr()) {255        // Yes it is, the location is valid.256        return true;257      }258 259      if (sc.function) {260        addr_t loclist_base_file_addr =261            sc.function->GetAddress().GetFileAddress();262        if (loclist_base_file_addr == LLDB_INVALID_ADDRESS)263          return false;264        // It is a location list. We just need to tell if the location list265        // contains the current address when converted to a load address266        return m_location_list.ContainsAddress(loclist_base_file_addr,267                                               address.GetFileAddress());268      }269    }270  }271  return false;272}273 274bool Variable::IsInScope(StackFrame *frame) {275  switch (m_scope) {276  case eValueTypeRegister:277  case eValueTypeRegisterSet:278    return frame != nullptr;279 280  case eValueTypeConstResult:281  case eValueTypeVariableGlobal:282  case eValueTypeVariableStatic:283  case eValueTypeVariableThreadLocal:284    return true;285 286  case eValueTypeVariableArgument:287  case eValueTypeVariableLocal:288    if (frame) {289      // We don't have a location list, we just need to see if the block that290      // this variable was defined in is currently291      Block *deepest_frame_block =292          frame->GetSymbolContext(eSymbolContextBlock).block;293      Address frame_addr = frame->GetFrameCodeAddress();294      if (deepest_frame_block)295        return IsInScope(*deepest_frame_block, frame_addr);296    }297    break;298 299  default:300    break;301  }302  return false;303}304 305bool Variable::IsInScope(const Block &block, const Address &addr) {306  SymbolContext variable_sc;307  CalculateSymbolContext(&variable_sc);308 309  // Check for static or global variable defined at the compile unit310  // level that wasn't defined in a block311  if (variable_sc.block == nullptr)312    return true;313 314  // Check if the variable is valid in the current block315  if (variable_sc.block != &block && !variable_sc.block->Contains(&block))316    return false;317 318  // If no scope range is specified then it means that the scope is the319  // same as the scope of the enclosing lexical block.320  if (m_scope_range.IsEmpty())321    return true;322 323  return m_scope_range.FindEntryThatContains(addr.GetFileAddress()) != nullptr;324}325 326Status Variable::GetValuesForVariableExpressionPath(327    llvm::StringRef variable_expr_path, ExecutionContextScope *scope,328    GetVariableCallback callback, void *baton, VariableList &variable_list,329    ValueObjectList &valobj_list) {330  Status error;331  if (!callback || variable_expr_path.empty()) {332    error = Status::FromErrorString("unknown error");333    return error;334  }335 336  switch (variable_expr_path.front()) {337  case '*':338    error = Variable::GetValuesForVariableExpressionPath(339        variable_expr_path.drop_front(), scope, callback, baton, variable_list,340        valobj_list);341    if (error.Fail()) {342      error = Status::FromErrorString("unknown error");343      return error;344    }345    for (uint32_t i = 0; i < valobj_list.GetSize();) {346      Status tmp_error;347      ValueObjectSP valobj_sp(348          valobj_list.GetValueObjectAtIndex(i)->Dereference(tmp_error));349      if (tmp_error.Fail()) {350        variable_list.RemoveVariableAtIndex(i);351        valobj_list.RemoveValueObjectAtIndex(i);352      } else {353        valobj_list.SetValueObjectAtIndex(i, valobj_sp);354        ++i;355      }356    }357    return error;358  case '&': {359    error = Variable::GetValuesForVariableExpressionPath(360        variable_expr_path.drop_front(), scope, callback, baton, variable_list,361        valobj_list);362    if (error.Success()) {363      for (uint32_t i = 0; i < valobj_list.GetSize();) {364        Status tmp_error;365        ValueObjectSP valobj_sp(366            valobj_list.GetValueObjectAtIndex(i)->AddressOf(tmp_error));367        if (tmp_error.Fail()) {368          variable_list.RemoveVariableAtIndex(i);369          valobj_list.RemoveValueObjectAtIndex(i);370        } else {371          valobj_list.SetValueObjectAtIndex(i, valobj_sp);372          ++i;373        }374      }375    } else {376      error = Status::FromErrorString("unknown error");377    }378    return error;379  } break;380 381  default: {382    static RegularExpression g_regex(383        llvm::StringRef("^([A-Za-z_:][A-Za-z_0-9:]*)(.*)"));384    llvm::SmallVector<llvm::StringRef, 2> matches;385    variable_list.Clear();386    if (!g_regex.Execute(variable_expr_path, &matches)) {387      error = Status::FromErrorStringWithFormatv(388          "unable to extract a variable name from '{0}'", variable_expr_path);389      return error;390    }391    std::string variable_name = matches[1].str();392    if (!callback(baton, variable_name.c_str(), variable_list)) {393      error = Status::FromErrorString("unknown error");394      return error;395    }396    uint32_t i = 0;397    while (i < variable_list.GetSize()) {398      VariableSP var_sp(variable_list.GetVariableAtIndex(i));399      ValueObjectSP valobj_sp;400      if (!var_sp) {401        variable_list.RemoveVariableAtIndex(i);402        continue;403      }404      ValueObjectSP variable_valobj_sp(405          ValueObjectVariable::Create(scope, var_sp));406      if (!variable_valobj_sp) {407        variable_list.RemoveVariableAtIndex(i);408        continue;409      }410 411      llvm::StringRef variable_sub_expr_path =412          variable_expr_path.drop_front(variable_name.size());413      if (!variable_sub_expr_path.empty()) {414        valobj_sp = variable_valobj_sp->GetValueForExpressionPath(415            variable_sub_expr_path);416        if (!valobj_sp) {417          error = Status::FromErrorStringWithFormatv(418              "invalid expression path '{0}' for variable '{1}'",419              variable_sub_expr_path, var_sp->GetName().GetCString());420          variable_list.RemoveVariableAtIndex(i);421          continue;422        }423      } else {424        // Just the name of a variable with no extras425        valobj_sp = variable_valobj_sp;426      }427 428      valobj_list.Append(valobj_sp);429      ++i;430    }431 432    if (variable_list.GetSize() > 0) {433      error.Clear();434      return error;435    }436  } break;437  }438  error = Status::FromErrorString("unknown error");439  return error;440}441 442bool Variable::DumpLocations(Stream *s, const Address &address) {443  SymbolContext sc;444  CalculateSymbolContext(&sc);445  ABISP abi;446  if (m_owner_scope) {447    ModuleSP module_sp(m_owner_scope->CalculateSymbolContextModule());448    if (module_sp)449      abi = ABI::FindPlugin(ProcessSP(), module_sp->GetArchitecture());450  }451 452  const addr_t file_addr = address.GetFileAddress();453  if (sc.function) {454    addr_t loclist_base_file_addr = sc.function->GetAddress().GetFileAddress();455    if (loclist_base_file_addr == LLDB_INVALID_ADDRESS)456      return false;457    return m_location_list.DumpLocations(s, eDescriptionLevelBrief,458                                         loclist_base_file_addr, file_addr,459                                         abi.get());460  }461  return false;462}463 464static void PrivateAutoComplete(465    StackFrame *frame, llvm::StringRef partial_path,466    const llvm::Twine467        &prefix_path, // Anything that has been resolved already will be in here468    const CompilerType &compiler_type, CompletionRequest &request);469 470static void PrivateAutoCompleteMembers(471    StackFrame *frame, const std::string &partial_member_name,472    llvm::StringRef partial_path,473    const llvm::Twine474        &prefix_path, // Anything that has been resolved already will be in here475    const CompilerType &compiler_type, CompletionRequest &request) {476 477  // We are in a type parsing child members478  const uint32_t num_bases = compiler_type.GetNumDirectBaseClasses();479 480  if (num_bases > 0) {481    for (uint32_t i = 0; i < num_bases; ++i) {482      CompilerType base_class_type =483          compiler_type.GetDirectBaseClassAtIndex(i, nullptr);484 485      PrivateAutoCompleteMembers(frame, partial_member_name, partial_path,486                                 prefix_path,487                                 base_class_type.GetCanonicalType(), request);488    }489  }490 491  const uint32_t num_vbases = compiler_type.GetNumVirtualBaseClasses();492 493  if (num_vbases > 0) {494    for (uint32_t i = 0; i < num_vbases; ++i) {495      CompilerType vbase_class_type =496          compiler_type.GetVirtualBaseClassAtIndex(i, nullptr);497 498      PrivateAutoCompleteMembers(frame, partial_member_name, partial_path,499                                 prefix_path,500                                 vbase_class_type.GetCanonicalType(), request);501    }502  }503 504  // We are in a type parsing child members505  const uint32_t num_fields = compiler_type.GetNumFields();506 507  if (num_fields > 0) {508    for (uint32_t i = 0; i < num_fields; ++i) {509      std::string member_name;510 511      CompilerType member_compiler_type = compiler_type.GetFieldAtIndex(512          i, member_name, nullptr, nullptr, nullptr);513 514      if (partial_member_name.empty()) {515        request.AddCompletion((prefix_path + member_name).str());516      } else if (llvm::StringRef(member_name)517                     .starts_with(partial_member_name)) {518        if (member_name == partial_member_name) {519          PrivateAutoComplete(520              frame, partial_path,521              prefix_path + member_name, // Anything that has been resolved522                                         // already will be in here523              member_compiler_type.GetCanonicalType(), request);524        } else if (partial_path.empty()) {525          request.AddCompletion((prefix_path + member_name).str());526        }527      }528    }529  }530}531 532static void PrivateAutoComplete(533    StackFrame *frame, llvm::StringRef partial_path,534    const llvm::Twine535        &prefix_path, // Anything that has been resolved already will be in here536    const CompilerType &compiler_type, CompletionRequest &request) {537  //    printf ("\nPrivateAutoComplete()\n\tprefix_path = '%s'\n\tpartial_path =538  //    '%s'\n", prefix_path.c_str(), partial_path.c_str());539  std::string remaining_partial_path;540 541  const lldb::TypeClass type_class = compiler_type.GetTypeClass();542  if (partial_path.empty()) {543    if (compiler_type.IsValid()) {544      switch (type_class) {545      default:546      case eTypeClassArray:547      case eTypeClassBlockPointer:548      case eTypeClassBuiltin:549      case eTypeClassComplexFloat:550      case eTypeClassComplexInteger:551      case eTypeClassEnumeration:552      case eTypeClassFunction:553      case eTypeClassMemberPointer:554      case eTypeClassReference:555      case eTypeClassTypedef:556      case eTypeClassVector: {557        request.AddCompletion(prefix_path.str());558      } break;559 560      case eTypeClassClass:561      case eTypeClassStruct:562      case eTypeClassUnion:563        if (prefix_path.str().back() != '.')564          request.AddCompletion((prefix_path + ".").str());565        break;566 567      case eTypeClassObjCObject:568      case eTypeClassObjCInterface:569        break;570      case eTypeClassObjCObjectPointer:571      case eTypeClassPointer: {572        bool omit_empty_base_classes = true;573        if (llvm::expectedToStdOptional(574                compiler_type.GetNumChildren(omit_empty_base_classes, nullptr))575                .value_or(0))576          request.AddCompletion((prefix_path + "->").str());577        else {578          request.AddCompletion(prefix_path.str());579        }580      } break;581      }582    } else {583      if (frame) {584        const bool get_file_globals = true;585 586        VariableList *variable_list = frame->GetVariableList(get_file_globals,587                                                             nullptr);588 589        if (variable_list) {590          for (const VariableSP &var_sp : *variable_list)591            request.AddCompletion(var_sp->GetName().AsCString());592        }593      }594    }595  } else {596    const char ch = partial_path[0];597    switch (ch) {598    case '*':599      if (prefix_path.str().empty()) {600        PrivateAutoComplete(frame, partial_path.substr(1), "*", compiler_type,601                            request);602      }603      break;604 605    case '&':606      if (prefix_path.isTriviallyEmpty()) {607        PrivateAutoComplete(frame, partial_path.substr(1), std::string("&"),608                            compiler_type, request);609      }610      break;611 612    case '-':613      if (partial_path.size() > 1 && partial_path[1] == '>' &&614          !prefix_path.str().empty()) {615        switch (type_class) {616        case lldb::eTypeClassPointer: {617          CompilerType pointee_type(compiler_type.GetPointeeType());618          if (partial_path.size() > 2 && partial_path[2]) {619            // If there is more after the "->", then search deeper620            PrivateAutoComplete(frame, partial_path.substr(2),621                                prefix_path + "->",622                                pointee_type.GetCanonicalType(), request);623          } else {624            // Nothing after the "->", so list all members625            PrivateAutoCompleteMembers(626                frame, std::string(), std::string(), prefix_path + "->",627                pointee_type.GetCanonicalType(), request);628          }629        } break;630        default:631          break;632        }633      }634      break;635 636    case '.':637      if (compiler_type.IsValid()) {638        switch (type_class) {639        case lldb::eTypeClassUnion:640        case lldb::eTypeClassStruct:641        case lldb::eTypeClassClass:642          if (partial_path.size() > 1 && partial_path[1]) {643            // If there is more after the ".", then search deeper644            PrivateAutoComplete(frame, partial_path.substr(1),645                                prefix_path + ".", compiler_type, request);646 647          } else {648            // Nothing after the ".", so list all members649            PrivateAutoCompleteMembers(frame, std::string(), partial_path,650                                       prefix_path + ".", compiler_type,651                                       request);652          }653          break;654        default:655          break;656        }657      }658      break;659    default:660      if (isalpha(ch) || ch == '_' || ch == '$') {661        const size_t partial_path_len = partial_path.size();662        size_t pos = 1;663        while (pos < partial_path_len) {664          const char curr_ch = partial_path[pos];665          if (isalnum(curr_ch) || curr_ch == '_' || curr_ch == '$') {666            ++pos;667            continue;668          }669          break;670        }671 672        std::string token(std::string(partial_path), 0, pos);673        remaining_partial_path = std::string(partial_path.substr(pos));674 675        if (compiler_type.IsValid()) {676          PrivateAutoCompleteMembers(frame, token, remaining_partial_path,677                                     prefix_path, compiler_type, request);678        } else if (frame) {679          // We haven't found our variable yet680          const bool get_file_globals = true;681 682          VariableList *variable_list =683              frame->GetVariableList(get_file_globals, nullptr);684 685          if (!variable_list)686            break;687 688          for (VariableSP var_sp : *variable_list) {689 690            if (!var_sp)691              continue;692 693            llvm::StringRef variable_name = var_sp->GetName().GetStringRef();694            if (variable_name.starts_with(token)) {695              if (variable_name == token) {696                Type *variable_type = var_sp->GetType();697                if (variable_type) {698                  CompilerType variable_compiler_type(699                      variable_type->GetForwardCompilerType());700                  PrivateAutoComplete(701                      frame, remaining_partial_path,702                      prefix_path + token, // Anything that has been resolved703                                           // already will be in here704                      variable_compiler_type.GetCanonicalType(), request);705                } else {706                  request.AddCompletion((prefix_path + variable_name).str());707                }708              } else if (remaining_partial_path.empty()) {709                request.AddCompletion((prefix_path + variable_name).str());710              }711            }712          }713        }714      }715      break;716    }717  }718}719 720void Variable::AutoComplete(const ExecutionContext &exe_ctx,721                            CompletionRequest &request) {722  CompilerType compiler_type;723 724  PrivateAutoComplete(exe_ctx.GetFramePtr(), request.GetCursorArgumentPrefix(),725                      "", compiler_type, request);726}727