summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/lit/SymbolFile/PDB/Inputs/VariablesTest.cpp50
-rw-r--r--lldb/lit/SymbolFile/PDB/variables.test58
-rw-r--r--lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp304
-rw-r--r--lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h12
4 files changed, 420 insertions, 4 deletions
diff --git a/lldb/lit/SymbolFile/PDB/Inputs/VariablesTest.cpp b/lldb/lit/SymbolFile/PDB/Inputs/VariablesTest.cpp
new file mode 100644
index 00000000000..304d9056609
--- /dev/null
+++ b/lldb/lit/SymbolFile/PDB/Inputs/VariablesTest.cpp
@@ -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;
+}
diff --git a/lldb/lit/SymbolFile/PDB/variables.test b/lldb/lit/SymbolFile/PDB/variables.test
new file mode 100644
index 00000000000..95d6d25d14b
--- /dev/null
+++ b/lldb/lit/SymbolFile/PDB/variables.test
@@ -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@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@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@Class@@QEAAXXZ
+CHECK-NEXT: Block{[[FID4]]}
+CHECK-DAG: Variable{{.*}}, name = "this"
+CHECK-SAME: scope = parameter
+CHECK-SAME: artificial \ No newline at end of file
diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
index 06d6087f31c..e490433fac0 100644
--- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
@@ -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 lldb_private::SymbolContext &sc) {
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::ResolveSymbolContext(
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,
diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
index fea2e7d0051..177eef9d5e9 100644
--- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
+++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
@@ -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;
OpenPOWER on IntegriCloud