llvm-project/lldb/source/Symbol/SymbolVendor.cpp

490 lines
16 KiB
C++
Raw Normal View History

//===-- SymbolVendor.cpp ----------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
<rdar://problem/11757916> Make breakpoint setting by file and line much more efficient by only looking for inlined breakpoint locations if we are setting a breakpoint in anything but a source implementation file. Implementing this complex for a many reasons. Turns out that parsing compile units lazily had some issues with respect to how we need to do things with DWARF in .o files. So the fixes in the checkin for this makes these changes: - Add a new setting called "target.inline-breakpoint-strategy" which can be set to "never", "always", or "headers". "never" will never try and set any inlined breakpoints (fastest). "always" always looks for inlined breakpoint locations (slowest, but most accurate). "headers", which is the default setting, will only look for inlined breakpoint locations if the breakpoint is set in what are consudered to be header files, which is realy defined as "not in an implementation source file". - modify the breakpoint setting by file and line to check the current "target.inline-breakpoint-strategy" setting and act accordingly - Modify compile units to be able to get their language and other info lazily. This allows us to create compile units from the debug map and not have to fill all of the details in, and then lazily discover this information as we go on debuggging. This is needed to avoid parsing all .o files when setting breakpoints in implementation only files (no inlines). Otherwise we would need to parse the .o file, the object file (mach-o in our case) and the symbol file (DWARF in the object file) just to see what the compile unit was. - modify the "SymbolFileDWARFDebugMap" to subclass lldb_private::Module so that the virtual "GetObjectFile()" and "GetSymbolVendor()" functions can be intercepted when the .o file contenst are later lazilly needed. Prior to this fix, when we first instantiated the "SymbolFileDWARFDebugMap" class, we would also make modules, object files and symbol files for every .o file in the debug map because we needed to fix up the sections in the .o files with information that is in the executable debug map. Now we lazily do this in the DebugMapModule::GetObjectFile() Cleaned up header includes a bit as well. llvm-svn: 162860
2012-08-30 05:13:06 +08:00
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
// FindPlugin
//
// Platforms can register a callback to use when creating symbol vendors to
// allow for complex debug information file setups, and to also allow for
// finding separate debug information files.
SymbolVendor *SymbolVendor::FindPlugin(const lldb::ModuleSP &module_sp,
lldb_private::Stream *feedback_strm) {
std::unique_ptr<SymbolVendor> instance_up;
SymbolVendorCreateInstance create_callback;
for (size_t idx = 0;
(create_callback = PluginManager::GetSymbolVendorCreateCallbackAtIndex(
idx)) != nullptr;
++idx) {
instance_up.reset(create_callback(module_sp, feedback_strm));
if (instance_up) {
return instance_up.release();
}
}
// The default implementation just tries to create debug information using
// the file representation for the module.
ObjectFileSP sym_objfile_sp;
FileSpec sym_spec = module_sp->GetSymbolFileFileSpec();
if (sym_spec && sym_spec != module_sp->GetObjectFile()->GetFileSpec()) {
DataBufferSP data_sp;
offset_t data_offset = 0;
sym_objfile_sp = ObjectFile::FindPlugin(
module_sp, &sym_spec, 0, FileSystem::Instance().GetByteSize(sym_spec),
data_sp, data_offset);
}
if (!sym_objfile_sp)
sym_objfile_sp = module_sp->GetObjectFile()->shared_from_this();
instance_up.reset(new SymbolVendor(module_sp));
instance_up->AddSymbolFileRepresentation(sym_objfile_sp);
return instance_up.release();
}
// SymbolVendor constructor
SymbolVendor::SymbolVendor(const lldb::ModuleSP &module_sp)
: ModuleChild(module_sp), m_type_list(), m_compile_units(), m_sym_file_up(),
m_symtab() {}
// Destructor
SymbolVendor::~SymbolVendor() {}
// Add a representation given an object file.
void SymbolVendor::AddSymbolFileRepresentation(const ObjectFileSP &objfile_sp) {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (objfile_sp) {
m_objfile_sp = objfile_sp;
m_sym_file_up.reset(SymbolFile::FindPlugin(objfile_sp.get()));
}
}
}
bool SymbolVendor::SetCompileUnitAtIndex(size_t idx, const CompUnitSP &cu_sp) {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
const size_t num_compile_units = GetNumCompileUnits();
if (idx < num_compile_units) {
// Fire off an assertion if this compile unit already exists for now. The
// partial parsing should take care of only setting the compile unit
// once, so if this assertion fails, we need to make sure that we don't
// have a race condition, or have a second parse of the same compile
// unit.
assert(m_compile_units[idx].get() == nullptr);
m_compile_units[idx] = cu_sp;
return true;
} else {
// This should NOT happen, and if it does, we want to crash and know
// about it
assert(idx < num_compile_units);
}
}
return false;
}
size_t SymbolVendor::GetNumCompileUnits() {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_compile_units.empty()) {
if (m_sym_file_up) {
// Resize our array of compile unit shared pointers -- which will each
// remain NULL until someone asks for the actual compile unit
// information. When this happens, the symbol file will be asked to
// parse this compile unit information.
m_compile_units.resize(m_sym_file_up->GetNumCompileUnits());
}
}
}
return m_compile_units.size();
}
lldb::LanguageType SymbolVendor::ParseLanguage(CompileUnit &comp_unit) {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_sym_file_up)
return m_sym_file_up->ParseLanguage(comp_unit);
}
return eLanguageTypeUnknown;
}
size_t SymbolVendor::ParseFunctions(CompileUnit &comp_unit) {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_sym_file_up)
return m_sym_file_up->ParseFunctions(comp_unit);
}
return 0;
<rdar://problem/11757916> Make breakpoint setting by file and line much more efficient by only looking for inlined breakpoint locations if we are setting a breakpoint in anything but a source implementation file. Implementing this complex for a many reasons. Turns out that parsing compile units lazily had some issues with respect to how we need to do things with DWARF in .o files. So the fixes in the checkin for this makes these changes: - Add a new setting called "target.inline-breakpoint-strategy" which can be set to "never", "always", or "headers". "never" will never try and set any inlined breakpoints (fastest). "always" always looks for inlined breakpoint locations (slowest, but most accurate). "headers", which is the default setting, will only look for inlined breakpoint locations if the breakpoint is set in what are consudered to be header files, which is realy defined as "not in an implementation source file". - modify the breakpoint setting by file and line to check the current "target.inline-breakpoint-strategy" setting and act accordingly - Modify compile units to be able to get their language and other info lazily. This allows us to create compile units from the debug map and not have to fill all of the details in, and then lazily discover this information as we go on debuggging. This is needed to avoid parsing all .o files when setting breakpoints in implementation only files (no inlines). Otherwise we would need to parse the .o file, the object file (mach-o in our case) and the symbol file (DWARF in the object file) just to see what the compile unit was. - modify the "SymbolFileDWARFDebugMap" to subclass lldb_private::Module so that the virtual "GetObjectFile()" and "GetSymbolVendor()" functions can be intercepted when the .o file contenst are later lazilly needed. Prior to this fix, when we first instantiated the "SymbolFileDWARFDebugMap" class, we would also make modules, object files and symbol files for every .o file in the debug map because we needed to fix up the sections in the .o files with information that is in the executable debug map. Now we lazily do this in the DebugMapModule::GetObjectFile() Cleaned up header includes a bit as well. llvm-svn: 162860
2012-08-30 05:13:06 +08:00
}
bool SymbolVendor::ParseLineTable(CompileUnit &comp_unit) {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_sym_file_up)
return m_sym_file_up->ParseLineTable(comp_unit);
}
return false;
}
<rdar://problem/11757916> Make breakpoint setting by file and line much more efficient by only looking for inlined breakpoint locations if we are setting a breakpoint in anything but a source implementation file. Implementing this complex for a many reasons. Turns out that parsing compile units lazily had some issues with respect to how we need to do things with DWARF in .o files. So the fixes in the checkin for this makes these changes: - Add a new setting called "target.inline-breakpoint-strategy" which can be set to "never", "always", or "headers". "never" will never try and set any inlined breakpoints (fastest). "always" always looks for inlined breakpoint locations (slowest, but most accurate). "headers", which is the default setting, will only look for inlined breakpoint locations if the breakpoint is set in what are consudered to be header files, which is realy defined as "not in an implementation source file". - modify the breakpoint setting by file and line to check the current "target.inline-breakpoint-strategy" setting and act accordingly - Modify compile units to be able to get their language and other info lazily. This allows us to create compile units from the debug map and not have to fill all of the details in, and then lazily discover this information as we go on debuggging. This is needed to avoid parsing all .o files when setting breakpoints in implementation only files (no inlines). Otherwise we would need to parse the .o file, the object file (mach-o in our case) and the symbol file (DWARF in the object file) just to see what the compile unit was. - modify the "SymbolFileDWARFDebugMap" to subclass lldb_private::Module so that the virtual "GetObjectFile()" and "GetSymbolVendor()" functions can be intercepted when the .o file contenst are later lazilly needed. Prior to this fix, when we first instantiated the "SymbolFileDWARFDebugMap" class, we would also make modules, object files and symbol files for every .o file in the debug map because we needed to fix up the sections in the .o files with information that is in the executable debug map. Now we lazily do this in the DebugMapModule::GetObjectFile() Cleaned up header includes a bit as well. llvm-svn: 162860
2012-08-30 05:13:06 +08:00
bool SymbolVendor::ParseDebugMacros(CompileUnit &comp_unit) {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_sym_file_up)
return m_sym_file_up->ParseDebugMacros(comp_unit);
}
return false;
}
bool SymbolVendor::ParseSupportFiles(CompileUnit &comp_unit,
FileSpecList &support_files) {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_sym_file_up)
return m_sym_file_up->ParseSupportFiles(comp_unit, support_files);
}
return false;
}
bool SymbolVendor::ParseIsOptimized(CompileUnit &comp_unit) {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_sym_file_up)
return m_sym_file_up->ParseIsOptimized(comp_unit);
}
return false;
}
bool SymbolVendor::ParseImportedModules(
const SymbolContext &sc, std::vector<SourceModule> &imported_modules) {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_sym_file_up)
return m_sym_file_up->ParseImportedModules(sc, imported_modules);
}
return false;
}
size_t SymbolVendor::ParseBlocksRecursive(Function &func) {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_sym_file_up)
return m_sym_file_up->ParseBlocksRecursive(func);
}
return 0;
}
size_t SymbolVendor::ParseTypes(CompileUnit &comp_unit) {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_sym_file_up)
return m_sym_file_up->ParseTypes(comp_unit);
}
return 0;
}
size_t SymbolVendor::ParseVariablesForContext(const SymbolContext &sc) {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_sym_file_up)
return m_sym_file_up->ParseVariablesForContext(sc);
}
return 0;
}
Type *SymbolVendor::ResolveTypeUID(lldb::user_id_t type_uid) {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_sym_file_up)
return m_sym_file_up->ResolveTypeUID(type_uid);
}
return nullptr;
}
uint32_t SymbolVendor::ResolveSymbolContext(const Address &so_addr,
SymbolContextItem resolve_scope,
SymbolContext &sc) {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_sym_file_up)
return m_sym_file_up->ResolveSymbolContext(so_addr, resolve_scope, sc);
}
return 0;
}
uint32_t SymbolVendor::ResolveSymbolContext(const FileSpec &file_spec,
uint32_t line, bool check_inlines,
SymbolContextItem resolve_scope,
SymbolContextList &sc_list) {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_sym_file_up)
return m_sym_file_up->ResolveSymbolContext(file_spec, line, check_inlines,
resolve_scope, sc_list);
}
return 0;
}
size_t
SymbolVendor::FindGlobalVariables(ConstString name,
const CompilerDeclContext *parent_decl_ctx,
size_t max_matches, VariableList &variables) {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_sym_file_up)
return m_sym_file_up->FindGlobalVariables(name, parent_decl_ctx,
max_matches, variables);
}
return 0;
}
size_t SymbolVendor::FindGlobalVariables(const RegularExpression &regex,
size_t max_matches,
VariableList &variables) {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_sym_file_up)
return m_sym_file_up->FindGlobalVariables(regex, max_matches, variables);
}
return 0;
}
size_t SymbolVendor::FindFunctions(ConstString name,
const CompilerDeclContext *parent_decl_ctx,
FunctionNameType name_type_mask,
bool include_inlines, bool append,
SymbolContextList &sc_list) {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_sym_file_up)
return m_sym_file_up->FindFunctions(name, parent_decl_ctx, name_type_mask,
include_inlines, append, sc_list);
}
return 0;
}
size_t SymbolVendor::FindFunctions(const RegularExpression &regex,
bool include_inlines, bool append,
SymbolContextList &sc_list) {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_sym_file_up)
return m_sym_file_up->FindFunctions(regex, include_inlines, append,
sc_list);
}
return 0;
}
size_t SymbolVendor::FindTypes(
ConstString name, const CompilerDeclContext *parent_decl_ctx,
bool append, size_t max_matches,
llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
TypeMap &types) {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_sym_file_up)
return m_sym_file_up->FindTypes(name, parent_decl_ctx, append,
max_matches, searched_symbol_files,
types);
}
if (!append)
types.Clear();
return 0;
}
size_t SymbolVendor::FindTypes(const std::vector<CompilerContext> &context,
bool append, TypeMap &types) {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_sym_file_up)
return m_sym_file_up->FindTypes(context, append, types);
}
if (!append)
types.Clear();
return 0;
}
size_t SymbolVendor::GetTypes(SymbolContextScope *sc_scope, TypeClass type_mask,
lldb_private::TypeList &type_list) {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_sym_file_up)
return m_sym_file_up->GetTypes(sc_scope, type_mask, type_list);
}
return 0;
Added the ability to get a list of types from a SBModule or SBCompileUnit. Sebastien Metrot wanted this, and sent a hollowed out patch. I filled in the blanks and did the low level implementation. The new functions are: //------------------------------------------------------------------ /// Get all types matching \a type_mask from debug info in this /// module. /// /// @param[in] type_mask /// A bitfield that consists of one or more bits logically OR'ed /// together from the lldb::TypeClass enumeration. This allows /// you to request only structure types, or only class, struct /// and union types. Passing in lldb::eTypeClassAny will return /// all types found in the debug information for this module. /// /// @return /// A list of types in this module that match \a type_mask //------------------------------------------------------------------ lldb::SBTypeList SBModule::GetTypes (uint32_t type_mask) //------------------------------------------------------------------ /// Get all types matching \a type_mask from debug info in this /// compile unit. /// /// @param[in] type_mask /// A bitfield that consists of one or more bits logically OR'ed /// together from the lldb::TypeClass enumeration. This allows /// you to request only structure types, or only class, struct /// and union types. Passing in lldb::eTypeClassAny will return /// all types found in the debug information for this compile /// unit. /// /// @return /// A list of types in this compile unit that match \a type_mask //------------------------------------------------------------------ lldb::SBTypeList SBCompileUnit::GetTypes (uint32_t type_mask = lldb::eTypeClassAny); This lets you request types by filling out a mask that contains one or more bits from the lldb::TypeClass enumerations, so you can only get the types you really want. llvm-svn: 184251
2013-06-19 06:51:05 +08:00
}
Final bit of type system cleanup that abstracts declaration contexts into lldb_private::CompilerDeclContext and renames ClangType to CompilerType in many accessors and functions. Create a new "lldb_private::CompilerDeclContext" class that will replace all direct uses of "clang::DeclContext" when used in compiler agnostic code, yet still allow for conversion to clang::DeclContext subclasses by clang specific code. This completes the abstraction of type parsing by removing all "clang::" references from the SymbolFileDWARF. The new "lldb_private::CompilerDeclContext" class abstracts decl contexts found in compiler type systems so they can be used in internal API calls. The TypeSystem is required to support CompilerDeclContexts with new pure virtual functions that start with "DeclContext" in the member function names. Converted all code that used lldb_private::ClangNamespaceDecl over to use the new CompilerDeclContext class and removed the ClangNamespaceDecl.cpp and ClangNamespaceDecl.h files. Removed direct use of clang APIs from SBType and now use the abstract type systems to correctly explore types. Bulk renames for things that used to return a ClangASTType which is now CompilerType: "Type::GetClangFullType()" to "Type::GetFullCompilerType()" "Type::GetClangLayoutType()" to "Type::GetLayoutCompilerType()" "Type::GetClangForwardType()" to "Type::GetForwardCompilerType()" "Value::GetClangType()" to "Value::GetCompilerType()" "Value::SetClangType (const CompilerType &)" to "Value::SetCompilerType (const CompilerType &)" "ValueObject::GetClangType ()" to "ValueObject::GetCompilerType()" many more renames that are similar. llvm-svn: 245905
2015-08-25 07:46:31 +08:00
CompilerDeclContext
SymbolVendor::FindNamespace(ConstString name,
const CompilerDeclContext *parent_decl_ctx) {
CompilerDeclContext namespace_decl_ctx;
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_sym_file_up)
namespace_decl_ctx = m_sym_file_up->FindNamespace(name, parent_decl_ctx);
}
return namespace_decl_ctx;
}
void SymbolVendor::Dump(Stream *s) {
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
bool show_context = false;
s->Printf("%p: ", static_cast<void *>(this));
s->Indent();
s->PutCString("SymbolVendor");
if (m_sym_file_up) {
*s << " " << m_sym_file_up->GetPluginName();
ObjectFile *objfile = m_sym_file_up->GetObjectFile();
if (objfile) {
const FileSpec &objfile_file_spec = objfile->GetFileSpec();
if (objfile_file_spec) {
s->PutCString(" (");
objfile_file_spec.Dump(s);
s->PutChar(')');
}
}
}
s->EOL();
if (m_sym_file_up)
m_sym_file_up->Dump(*s);
s->IndentMore();
m_type_list.Dump(s, show_context);
CompileUnitConstIter cu_pos, cu_end;
cu_end = m_compile_units.end();
for (cu_pos = m_compile_units.begin(); cu_pos != cu_end; ++cu_pos) {
// We currently only dump the compile units that have been parsed
if (*cu_pos)
(*cu_pos)->Dump(s, show_context);
}
if (Symtab *symtab = GetSymtab())
symtab->Dump(s, nullptr, eSortOrderNone);
s->IndentLess();
}
}
CompUnitSP SymbolVendor::GetCompileUnitAtIndex(size_t idx) {
CompUnitSP cu_sp;
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
const size_t num_compile_units = GetNumCompileUnits();
if (idx < num_compile_units) {
cu_sp = m_compile_units[idx];
if (cu_sp.get() == nullptr) {
m_compile_units[idx] = m_sym_file_up->ParseCompileUnitAtIndex(idx);
cu_sp = m_compile_units[idx];
}
}
}
return cu_sp;
}
FileSpec SymbolVendor::GetMainFileSpec() const {
if (m_sym_file_up) {
const ObjectFile *symfile_objfile = m_sym_file_up->GetObjectFile();
if (symfile_objfile)
return symfile_objfile->GetFileSpec();
}
return FileSpec();
}
Symtab *SymbolVendor::GetSymtab() {
ModuleSP module_sp(GetModule());
if (!module_sp)
return nullptr;
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
if (m_symtab)
return m_symtab;
ObjectFile *objfile = module_sp->GetObjectFile();
if (!objfile)
return nullptr;
m_symtab = objfile->GetSymtab();
if (m_symtab && m_sym_file_up)
m_sym_file_up->AddSymbols(*m_symtab);
return m_symtab;
}
void SymbolVendor::ClearSymtab() {
ModuleSP module_sp(GetModule());
if (module_sp) {
ObjectFile *objfile = module_sp->GetObjectFile();
if (objfile) {
// Clear symbol table from unified section list.
objfile->ClearSymtab();
}
}
}
void SymbolVendor::SectionFileAddressesChanged() {
ModuleSP module_sp(GetModule());
if (module_sp) {
ObjectFile *module_objfile = module_sp->GetObjectFile();
if (m_sym_file_up) {
ObjectFile *symfile_objfile = m_sym_file_up->GetObjectFile();
if (symfile_objfile != module_objfile)
symfile_objfile->SectionFileAddressesChanged();
}
Symtab *symtab = GetSymtab();
if (symtab) {
symtab->SectionFileAddressesChanged();
}
}
}
// PluginInterface protocol
lldb_private::ConstString SymbolVendor::GetPluginName() {
static ConstString g_name("vendor-default");
return g_name;
}
uint32_t SymbolVendor::GetPluginVersion() { return 1; }