[Lldb-commits] [lldb] r333049 - [SymbolFilePDB] Add support for resolving variable symbols

Aaron Smith via lldb-commits lldb-commits at lists.llvm.org
Tue May 22 18:52:42 PDT 2018


Author: asmith
Date: Tue May 22 18:52:42 2018
New Revision: 333049

URL: http://llvm.org/viewvc/llvm-project?rev=333049&view=rev
Log:
[SymbolFilePDB] Add support for resolving variable symbols

Summary:
Implement FindGlobalVariables and ParseVariableContext methods.

Compile unit information is necessary for resolving variable context, however some PDB symbols do not have this information. For now an empty DWARFExpression is used to construct a lldb::Variable instance with the limitation that using lldb to lookup the value of a global or local variable is not available.

This commit may slow down lit/SymbolFile/PDB/compilands.test since the test includes MS specific modules that spend more time parsing variables.

Reviewers: rnk, zturner, lldb-commits

Subscribers: aprantl, JDevlieghere, llvm-commits

Differential Revision: https://reviews.llvm.org/D45224

Added:
    lldb/trunk/lit/SymbolFile/PDB/Inputs/VariablesTest.cpp
    lldb/trunk/lit/SymbolFile/PDB/variables.test
Modified:
    lldb/trunk/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
    lldb/trunk/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h

Added: lldb/trunk/lit/SymbolFile/PDB/Inputs/VariablesTest.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/PDB/Inputs/VariablesTest.cpp?rev=333049&view=auto
==============================================================================
--- lldb/trunk/lit/SymbolFile/PDB/Inputs/VariablesTest.cpp (added)
+++ lldb/trunk/lit/SymbolFile/PDB/Inputs/VariablesTest.cpp Tue May 22 18:52:42 2018
@@ -0,0 +1,50 @@
+typedef int IntTypedef;
+IntTypedef g_IntVar;  // Testing globals.
+
+typedef enum Enum { // Testing constants.
+  RED,
+  GREEN,
+  BLUE
+} EnumTypedef;
+EnumTypedef g_EnumVar;  // Testing members.
+
+// FIXME: `sg_IntVar` appears both in global scope's children and compiland's
+// children but with different symbol's id.
+static int sg_IntVar = -1;  // Testing file statics.
+
+// FIXME: `g_Const` appears both in global scope's children and compiland's
+// children but with different symbol's id.
+const int g_Const = 0x88;  // Testing constant data.
+const int *g_pConst = &g_Const; // Avoid optimizing the const away
+
+thread_local int g_tls = 0;  // Testing thread-local storage.
+
+class Class {
+  static int m_StaticClassMember;
+public:
+  explicit Class(int a) {}
+  void Func() {}
+};
+int Class::m_StaticClassMember = 10; // Testing static class members.
+Class ClassVar(1);
+
+int f(int var_arg1, int var_arg2) {  // Testing parameters.
+  long same_name_var = -1;
+  return 1;
+}
+
+int same_name_var = 100;
+int main() {
+  int same_name_var = 0;  // Testing locals.
+  const char local_const = 0x1;
+
+  // FIXME: 'local_CString` is not found through compiland's children.
+  const char local_CString[] = "abc";  // Testing constant string.
+  const char *local_pCString = local_CString; // Avoid optimizing the const away
+
+  int a = 10;
+  a++;
+
+  ClassVar.Func();
+  return 0;
+}

Added: lldb/trunk/lit/SymbolFile/PDB/variables.test
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/PDB/variables.test?rev=333049&view=auto
==============================================================================
--- lldb/trunk/lit/SymbolFile/PDB/variables.test (added)
+++ lldb/trunk/lit/SymbolFile/PDB/variables.test Tue May 22 18:52:42 2018
@@ -0,0 +1,58 @@
+REQUIRES: windows
+RUN: clang-cl /Z7 /c %S/Inputs/VariablesTest.cpp /o %T/VariablesTest.cpp.obj
+RUN: link %T/VariablesTest.cpp.obj /DEBUG /nodefaultlib /ENTRY:main /OUT:%T/VariablesTest.cpp.exe
+RUN: lldb-test symbols %T/VariablesTest.cpp.exe | FileCheck %s
+
+CHECK: Module [[MOD:.*]]
+CHECK: SymbolVendor ([[MOD]])
+CHECK:     CompileUnit{{.*}}, language = "c++", file = '{{.*}}\VariablesTest.cpp'
+CHECK-DAG:   Variable{{.*}}, name = "g_IntVar"
+CHECK-SAME:  scope = global, external
+CHECK-DAG:   Variable{{.*}}, name = "m_StaticClassMember"
+CHECK-SAME:  scope = global, external
+CHECK-DAG:   Variable{{.*}}, name = "g_pConst"
+CHECK-SAME:  scope = global, external
+CHECK-DAG:   Variable{{.*}}, name = "same_name_var"
+CHECK-SAME:  scope = global, external
+CHECK-DAG:   Variable{{.*}}, name = "g_EnumVar"
+CHECK-SAME:  scope = global, external
+CHECK-DAG:   Variable{{.*}}, name = "g_tls"
+CHECK-SAME:  scope = thread local, external
+CHECK-DAG:   Variable{{.*}}, name = "ClassVar"
+CHECK-SAME:  scope = global, external
+CHECK-DAG:   Variable{{.*}}, name = "g_Const"
+CHECK-SAME:  scope = ??? (2)
+
+CHECK-DAG:   Function{[[FID1:.*]]}, mangled = ?f@@YAHHH at Z
+CHECK-NEXT:  Block{[[FID1]]}
+CHECK-DAG:     Variable{{.*}}, name = "var_arg1"
+CHECK-SAME:    scope = parameter
+CHECK-DAG:     Variable{{.*}}, name = "var_arg2"
+CHECK-SAME:    scope = parameter
+CHECK-DAG:     Variable{{.*}}, name = "same_name_var"
+CHECK-SAME:    scope = local
+
+CHECK-DAG:   Function{[[FID2:.*]]}, mangled = main
+CHECK-NEXT:  Block{[[FID2]]}
+CHECK-DAG:     Variable{{.*}}, name = "same_name_var"
+CHECK-SAME:    scope = local
+CHECK-DAG:     Variable{{.*}}, name = "local_const"
+CHECK-SAME:    scope = local
+CHECK-DAG:     Variable{{.*}}, name = "local_pCString"
+CHECK-SAME:    scope = local
+CHECK-DAG:     Variable{{.*}}, name = "a"
+CHECK-SAME:    scope = local
+
+CHECK-DAG:   Function{[[FID3:.*]]}, mangled = ??0Class@@QEAA at H@Z
+CHECK-NEXT:  Block{[[FID3]]}
+CHECK-DAG:     Variable{{.*}}, name = "this"
+CHECK-SAME:    scope = parameter
+CHECK-SAME:    artificial
+CHECK-DAG:     Variable{{.*}}, name = "a"
+CHECK-SAME:    scope = parameter
+
+CHECK-DAG:   Function{[[FID4:.*]]}, mangled = ?Func at Class@@QEAAXXZ
+CHECK-NEXT:  Block{[[FID4]]}
+CHECK-DAG:     Variable{{.*}}, name = "this"
+CHECK-SAME:    scope = parameter
+CHECK-SAME:    artificial
\ No newline at end of file

Modified: lldb/trunk/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp?rev=333049&r1=333048&r2=333049&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp (original)
+++ lldb/trunk/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp Tue May 22 18:52:42 2018
@@ -21,6 +21,7 @@
 #include "lldb/Symbol/SymbolVendor.h"
 #include "lldb/Symbol/TypeList.h"
 #include "lldb/Symbol/TypeMap.h"
+#include "lldb/Symbol/Variable.h"
 #include "lldb/Utility/RegularExpression.h"
 
 #include "llvm/DebugInfo/PDB/GenericError.h"
@@ -483,8 +484,51 @@ size_t SymbolFilePDB::ParseTypes(const l
 
 size_t
 SymbolFilePDB::ParseVariablesForContext(const lldb_private::SymbolContext &sc) {
-  // TODO: Implement this
-  return size_t();
+  if (!sc.comp_unit)
+    return 0;
+
+  size_t num_added = 0;
+  if (sc.function) {
+    auto pdb_func = m_session_up->getConcreteSymbolById<PDBSymbolFunc>(
+        sc.function->GetID());
+    if (!pdb_func)
+      return 0;
+
+    num_added += ParseVariables(sc, *pdb_func);
+    sc.function->GetBlock(false).SetDidParseVariables(true, true);
+  } else if (sc.comp_unit) {
+    auto compiland = GetPDBCompilandByUID(sc.comp_unit->GetID());
+    if (!compiland)
+      return 0;
+
+    if (sc.comp_unit->GetVariableList(false))
+      return 0;
+
+    auto results = m_global_scope_up->findAllChildren<PDBSymbolData>();
+    if (results && results->getChildCount()) {
+      while (auto result = results->getNext()) {
+        auto cu_id = result->getCompilandId();
+        // FIXME: We are not able to determine variable's compile unit.
+        if (cu_id == 0)
+          continue;
+
+        if (cu_id == sc.comp_unit->GetID())
+          num_added += ParseVariables(sc, *result);
+      }
+    }
+
+    // FIXME: A `file static` or `global constant` variable appears both in
+    // compiland's children and global scope's children with unexpectedly
+    // different symbol's Id making it ambiguous.
+
+    // FIXME: 'local constant', for example, const char var[] = "abc", declared
+    // in a function scope, can't be found in PDB.
+
+    // Parse variables in this compiland.
+    num_added += ParseVariables(sc, *compiland);
+  }
+
+  return num_added;
 }
 
 lldb_private::Type *SymbolFilePDB::ResolveTypeUID(lldb::user_id_t type_uid) {
@@ -714,18 +758,270 @@ uint32_t SymbolFilePDB::ResolveSymbolCon
   return sc_list.GetSize() - old_size;
 }
 
+std::string SymbolFilePDB::GetMangledForPDBData(const PDBSymbolData &pdb_data) {
+  std::string decorated_name;
+  auto vm_addr = pdb_data.getVirtualAddress();
+  if (vm_addr != LLDB_INVALID_ADDRESS && vm_addr) {
+    auto result_up =
+        m_global_scope_up->findAllChildren(PDB_SymType::PublicSymbol);
+    if (result_up) {
+      while (auto symbol_up = result_up->getNext()) {
+        if (symbol_up->getRawSymbol().getVirtualAddress() == vm_addr) {
+          decorated_name = symbol_up->getRawSymbol().getName();
+          break;
+        }
+      }
+    }
+  }
+  if (!decorated_name.empty())
+    return decorated_name;
+
+  return std::string();
+}
+
+VariableSP SymbolFilePDB::ParseVariableForPDBData(
+    const lldb_private::SymbolContext &sc,
+    const llvm::pdb::PDBSymbolData &pdb_data) {
+  VariableSP var_sp;
+  uint32_t var_uid = pdb_data.getSymIndexId();
+  auto result = m_variables.find(var_uid);
+  if (result != m_variables.end())
+    return result->second;
+
+  ValueType scope = eValueTypeInvalid;
+  bool is_static_member = false;
+  bool is_external = false;
+  bool is_artificial = false;
+
+  switch (pdb_data.getDataKind()) {
+  case PDB_DataKind::Global:
+    scope = eValueTypeVariableGlobal;
+    is_external = true;
+    break;
+  case PDB_DataKind::Local:
+    scope = eValueTypeVariableLocal;
+    break;
+  case PDB_DataKind::FileStatic:
+    scope = eValueTypeVariableStatic;
+    break;
+  case PDB_DataKind::StaticMember:
+    is_static_member = true;
+    scope = eValueTypeVariableStatic;
+    break;
+  case PDB_DataKind::Member:
+    scope = eValueTypeVariableStatic;
+    break;
+  case PDB_DataKind::Param:
+    scope = eValueTypeVariableArgument;
+    break;
+  case PDB_DataKind::Constant:
+    scope = eValueTypeConstResult;
+    break;
+  default:
+    break;
+  }
+
+  switch (pdb_data.getLocationType()) {
+  case PDB_LocType::TLS:
+    scope = eValueTypeVariableThreadLocal;
+    break;
+  case PDB_LocType::RegRel: {
+    // It is a `this` pointer.
+    if (pdb_data.getDataKind() == PDB_DataKind::ObjectPtr) {
+      scope = eValueTypeVariableArgument;
+      is_artificial = true;
+    }
+  } break;
+  default:
+    break;
+  }
+
+  Declaration decl;
+  if (!is_artificial && !pdb_data.isCompilerGenerated()) {
+    if (auto lines = pdb_data.getLineNumbers()) {
+      if (auto first_line = lines->getNext()) {
+        uint32_t src_file_id = first_line->getSourceFileId();
+        auto src_file = m_session_up->getSourceFileById(src_file_id);
+        if (src_file) {
+          FileSpec spec(src_file->getFileName(), /*resolve_path*/ false);
+          decl.SetFile(spec);
+          decl.SetColumn(first_line->getColumnNumber());
+          decl.SetLine(first_line->getLineNumber());
+        }
+      }
+    }
+  }
+
+  Variable::RangeList ranges;
+  SymbolContextScope *context_scope = sc.comp_unit;
+  if (scope == eValueTypeVariableLocal) {
+    if (sc.function) {
+      context_scope = sc.function->GetBlock(true).FindBlockByID(
+          pdb_data.getClassParentId());
+      if (context_scope == nullptr)
+        context_scope = sc.function;
+    }
+  }
+
+  SymbolFileTypeSP type_sp =
+      std::make_shared<SymbolFileType>(*this, pdb_data.getTypeId());
+
+  auto var_name = pdb_data.getName();
+  auto mangled = GetMangledForPDBData(pdb_data);
+  auto mangled_cstr = mangled.empty() ? nullptr : mangled.c_str();
+
+  DWARFExpression location(nullptr);
+
+  var_sp = std::make_shared<Variable>(
+      var_uid, var_name.c_str(), mangled_cstr, type_sp, scope, context_scope,
+      ranges, &decl, location, is_external, is_artificial, is_static_member);
+
+  m_variables.insert(std::make_pair(var_uid, var_sp));
+  return var_sp;
+}
+
+size_t
+SymbolFilePDB::ParseVariables(const lldb_private::SymbolContext &sc,
+                              const llvm::pdb::PDBSymbol &pdb_symbol,
+                              lldb_private::VariableList *variable_list) {
+  size_t num_added = 0;
+
+  if (auto pdb_data = llvm::dyn_cast<PDBSymbolData>(&pdb_symbol)) {
+    VariableListSP local_variable_list_sp;
+
+    auto result = m_variables.find(pdb_data->getSymIndexId());
+    if (result != m_variables.end()) {
+      if (variable_list)
+        variable_list->AddVariableIfUnique(result->second);
+    } else {
+      // Prepare right VariableList for this variable.
+      if (auto lexical_parent = pdb_data->getLexicalParent()) {
+        switch (lexical_parent->getSymTag()) {
+        case PDB_SymType::Exe:
+          assert(sc.comp_unit);
+          LLVM_FALLTHROUGH;
+        case PDB_SymType::Compiland: {
+          if (sc.comp_unit) {
+            local_variable_list_sp = sc.comp_unit->GetVariableList(false);
+            if (!local_variable_list_sp) {
+              local_variable_list_sp = std::make_shared<VariableList>();
+              sc.comp_unit->SetVariableList(local_variable_list_sp);
+            }
+          }
+        } break;
+        case PDB_SymType::Block:
+        case PDB_SymType::Function: {
+          if (sc.function) {
+            Block *block = sc.function->GetBlock(true).FindBlockByID(
+                lexical_parent->getSymIndexId());
+            if (block) {
+              local_variable_list_sp = block->GetBlockVariableList(false);
+              if (!local_variable_list_sp) {
+                local_variable_list_sp = std::make_shared<VariableList>();
+                block->SetVariableList(local_variable_list_sp);
+              }
+            }
+          }
+        } break;
+        default:
+          break;
+        }
+      }
+
+      if (local_variable_list_sp) {
+        if (auto var_sp = ParseVariableForPDBData(sc, *pdb_data)) {
+          local_variable_list_sp->AddVariableIfUnique(var_sp);
+          if (variable_list)
+            variable_list->AddVariableIfUnique(var_sp);
+          ++num_added;
+        }
+      }
+    }
+  }
+
+  if (auto results = pdb_symbol.findAllChildren()) {
+    while (auto result = results->getNext())
+      num_added += ParseVariables(sc, *result, variable_list);
+  }
+
+  return num_added;
+}
+
 uint32_t SymbolFilePDB::FindGlobalVariables(
     const lldb_private::ConstString &name,
     const lldb_private::CompilerDeclContext *parent_decl_ctx, bool append,
     uint32_t max_matches, lldb_private::VariableList &variables) {
-  return uint32_t();
+  if (!append)
+    variables.Clear();
+  if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx))
+    return 0;
+  if (name.IsEmpty())
+    return 0;
+
+  auto results =
+      m_global_scope_up->findChildren(PDB_SymType::Data, name.GetStringRef(),
+                                      PDB_NameSearchFlags::NS_CaseSensitive);
+  if (!results)
+    return 0;
+
+  uint32_t matches = 0;
+  size_t old_size = variables.GetSize();
+  while (auto result = results->getNext()) {
+    auto pdb_data = llvm::dyn_cast<PDBSymbolData>(result.get());
+    if (max_matches > 0 && matches >= max_matches)
+      break;
+
+    SymbolContext sc;
+    sc.module_sp = m_obj_file->GetModule();
+    lldbassert(sc.module_sp.get());
+
+    sc.comp_unit = ParseCompileUnitForUID(pdb_data->getCompilandId()).get();
+    // FIXME: We are not able to determine the compile unit.
+    if (sc.comp_unit == nullptr)
+      continue;
+
+    ParseVariables(sc, *pdb_data, &variables);
+    matches = variables.GetSize() - old_size;
+  }
+
+  return matches;
 }
 
 uint32_t
 SymbolFilePDB::FindGlobalVariables(const lldb_private::RegularExpression &regex,
                                    bool append, uint32_t max_matches,
                                    lldb_private::VariableList &variables) {
-  return uint32_t();
+  if (!regex.IsValid())
+    return 0;
+  auto results = m_global_scope_up->findAllChildren<PDBSymbolData>();
+  if (!results)
+    return 0;
+
+  uint32_t matches = 0;
+  size_t old_size = variables.GetSize();
+  while (auto pdb_data = results->getNext()) {
+    if (max_matches > 0 && matches >= max_matches)
+      break;
+
+    auto var_name = pdb_data->getName();
+    if (var_name.empty())
+      continue;
+    if (!regex.Execute(var_name))
+      continue;
+    SymbolContext sc;
+    sc.module_sp = m_obj_file->GetModule();
+    lldbassert(sc.module_sp.get());
+
+    sc.comp_unit = ParseCompileUnitForUID(pdb_data->getCompilandId()).get();
+    // FIXME: We are not able to determine the compile unit.
+    if (sc.comp_unit == nullptr)
+      continue;
+
+    ParseVariables(sc, *pdb_data, &variables);
+    matches = variables.GetSize() - old_size;
+  }
+
+  return matches;
 }
 
 bool SymbolFilePDB::ResolveFunction(const llvm::pdb::PDBSymbolFunc &pdb_func,

Modified: lldb/trunk/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h?rev=333049&r1=333048&r2=333049&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h (original)
+++ lldb/trunk/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h Tue May 22 18:52:42 2018
@@ -12,6 +12,7 @@
 
 #include "lldb/Core/UniqueCStringMap.h"
 #include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/VariableList.h"
 #include "lldb/Utility/UserID.h"
 
 #include "llvm/ADT/DenseMap.h"
@@ -181,6 +182,16 @@ private:
   void FindTypesByName(const std::string &name, uint32_t max_matches,
                        lldb_private::TypeMap &types);
 
+  std::string GetMangledForPDBData(const llvm::pdb::PDBSymbolData &pdb_data);
+
+  lldb::VariableSP
+  ParseVariableForPDBData(const lldb_private::SymbolContext &sc,
+                          const llvm::pdb::PDBSymbolData &pdb_data);
+
+  size_t ParseVariables(const lldb_private::SymbolContext &sc,
+                        const llvm::pdb::PDBSymbol &pdb_data,
+                        lldb_private::VariableList *variable_list = nullptr);
+
   lldb::CompUnitSP
   GetCompileUnitContainsAddress(const lldb_private::Address &so_addr);
 
@@ -217,6 +228,7 @@ private:
 
   llvm::DenseMap<uint32_t, lldb::CompUnitSP> m_comp_units;
   llvm::DenseMap<uint32_t, lldb::TypeSP> m_types;
+  llvm::DenseMap<uint32_t, lldb::VariableSP> m_variables;
 
   std::vector<lldb::TypeSP> m_builtin_types;
   std::unique_ptr<llvm::pdb::IPDBSession> m_session_up;




More information about the lldb-commits mailing list