aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/SymbolFile
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2021-12-25 22:30:44 +0000
committerDimitry Andric <dim@FreeBSD.org>2021-12-25 22:30:44 +0000
commit77fc4c146f0870ffb09c1afb823ccbe742c5e6ff (patch)
tree5c0eb39553003b9c75a901af6bc4ddabd6f2f28c /lldb/source/Plugins/SymbolFile
parentf65dcba83ce5035ab88a85fe17628b447eb56e1b (diff)
Diffstat (limited to 'lldb/source/Plugins/SymbolFile')
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp5
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h2
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp11
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h12
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp133
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h6
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp2
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp30
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h12
-rw-r--r--lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp3
10 files changed, 176 insertions, 40 deletions
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 4ac6e165dda3..b90f104c4d21 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -1530,7 +1530,6 @@ TypeSP DWARFASTParserClang::UpdateSymbolContextScopeForType(
return type_sp;
SymbolFileDWARF *dwarf = die.GetDWARF();
- TypeList &type_list = dwarf->GetTypeList();
DWARFDIE sc_parent_die = SymbolFileDWARF::GetParentSymbolContextDIE(die);
dw_tag_t sc_parent_tag = sc_parent_die.Tag();
@@ -1550,10 +1549,6 @@ TypeSP DWARFASTParserClang::UpdateSymbolContextScopeForType(
if (symbol_context_scope != nullptr)
type_sp->SetSymbolContextScope(symbol_context_scope);
- // We are ready to put this type into the uniqued list up at the module
- // level.
- type_list.Insert(type_sp);
-
dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get();
return type_sp;
}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
index cece29dcf9ac..71d4c1e6c52f 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
@@ -153,7 +153,7 @@ public:
const DWARFAbbreviationDeclarationSet *GetAbbreviations() const;
dw_offset_t GetAbbrevOffset() const;
uint8_t GetAddressByteSize() const { return m_header.GetAddressByteSize(); }
- dw_addr_t GetAddrBase() const { return m_addr_base ? *m_addr_base : 0; }
+ dw_addr_t GetAddrBase() const { return m_addr_base.getValueOr(0); }
dw_addr_t GetBaseAddress() const { return m_base_addr; }
dw_offset_t GetLineTableOffset();
dw_addr_t GetRangesBase() const { return m_ranges_base; }
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 8c20244a6c44..8c995ef2eb2a 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -1097,7 +1097,8 @@ bool SymbolFileDWARF::ParseImportedModules(
if (const char *include_path = module_die.GetAttributeValueAsString(
DW_AT_LLVM_include_path, nullptr)) {
FileSpec include_spec(include_path, dwarf_cu->GetPathStyle());
- MakeAbsoluteAndRemap(include_spec, *dwarf_cu, m_objfile_sp->GetModule());
+ MakeAbsoluteAndRemap(include_spec, *dwarf_cu,
+ m_objfile_sp->GetModule());
module.search_path = ConstString(include_spec.GetPath());
}
if (const char *sysroot = dwarf_cu->DIE().GetAttributeValueAsString(
@@ -1924,7 +1925,7 @@ void SymbolFileDWARF::ResolveFunctionAndBlock(lldb::addr_t file_vm_addr,
block_die = function_die.LookupDeepestBlock(file_vm_addr);
}
- if (!sc.function || ! lookup_block)
+ if (!sc.function || !lookup_block)
return;
Block &block = sc.function->GetBlock(true);
@@ -2319,7 +2320,8 @@ void SymbolFileDWARF::FindFunctions(ConstString name,
if (log) {
GetObjectFile()->GetModule()->LogMessage(
log,
- "SymbolFileDWARF::FindFunctions (name=\"%s\", name_type_mask=0x%x, sc_list)",
+ "SymbolFileDWARF::FindFunctions (name=\"%s\", name_type_mask=0x%x, "
+ "sc_list)",
name.GetCString(), name_type_mask);
}
@@ -2352,8 +2354,7 @@ void SymbolFileDWARF::FindFunctions(ConstString name,
log,
"SymbolFileDWARF::FindFunctions (name=\"%s\", "
"name_type_mask=0x%x, include_inlines=%d, sc_list) => %u",
- name.GetCString(), name_type_mask, include_inlines,
- num_matches);
+ name.GetCString(), name_type_mask, include_inlines, num_matches);
}
}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index 271ce7be1eea..e81ce28cb86e 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -253,8 +253,8 @@ public:
ExternalTypeModuleMap;
/// Return the list of Clang modules imported by this SymbolFile.
- const ExternalTypeModuleMap& getExternalTypeModules() const {
- return m_external_type_modules;
+ const ExternalTypeModuleMap &getExternalTypeModules() const {
+ return m_external_type_modules;
}
virtual DWARFDIE GetDIE(const DIERef &die_ref);
@@ -328,7 +328,6 @@ public:
return m_parse_time;
}
-
protected:
typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb_private::Type *>
DIEToTypePtr;
@@ -428,9 +427,10 @@ protected:
virtual lldb::TypeSP
FindDefinitionTypeForDWARFDeclContext(const DWARFDeclContext &die_decl_ctx);
- virtual lldb::TypeSP FindCompleteObjCDefinitionTypeForDIE(
- const DWARFDIE &die, lldb_private::ConstString type_name,
- bool must_be_implementation);
+ virtual lldb::TypeSP
+ FindCompleteObjCDefinitionTypeForDIE(const DWARFDIE &die,
+ lldb_private::ConstString type_name,
+ bool must_be_implementation);
lldb_private::Symbol *
GetObjCClassSymbol(lldb_private::ConstString objc_class_name);
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
index c29fc2230a67..9473befa6cc3 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
@@ -30,6 +30,70 @@ using namespace lldb_private::npdb;
using namespace llvm::codeview;
using namespace llvm::pdb;
+namespace {
+struct CreateMethodDecl : public TypeVisitorCallbacks {
+ CreateMethodDecl(PdbIndex &m_index, TypeSystemClang &m_clang,
+ TypeIndex func_type_index,
+ clang::FunctionDecl *&function_decl,
+ lldb::opaque_compiler_type_t parent_ty,
+ llvm::StringRef proc_name, CompilerType func_ct)
+ : m_index(m_index), m_clang(m_clang), func_type_index(func_type_index),
+ function_decl(function_decl), parent_ty(parent_ty),
+ proc_name(proc_name), func_ct(func_ct) {}
+ PdbIndex &m_index;
+ TypeSystemClang &m_clang;
+ TypeIndex func_type_index;
+ clang::FunctionDecl *&function_decl;
+ lldb::opaque_compiler_type_t parent_ty;
+ llvm::StringRef proc_name;
+ CompilerType func_ct;
+
+ llvm::Error visitKnownMember(CVMemberRecord &cvr,
+ OverloadedMethodRecord &overloaded) override {
+ TypeIndex method_list_idx = overloaded.MethodList;
+
+ CVType method_list_type = m_index.tpi().getType(method_list_idx);
+ assert(method_list_type.kind() == LF_METHODLIST);
+
+ MethodOverloadListRecord method_list;
+ llvm::cantFail(TypeDeserializer::deserializeAs<MethodOverloadListRecord>(
+ method_list_type, method_list));
+
+ for (const OneMethodRecord &method : method_list.Methods) {
+ if (method.getType().getIndex() == func_type_index.getIndex())
+ AddMethod(overloaded.Name, method.getAccess(), method.getOptions(),
+ method.Attrs);
+ }
+
+ return llvm::Error::success();
+ }
+
+ llvm::Error visitKnownMember(CVMemberRecord &cvr,
+ OneMethodRecord &record) override {
+ AddMethod(record.getName(), record.getAccess(), record.getOptions(),
+ record.Attrs);
+ return llvm::Error::success();
+ }
+
+ void AddMethod(llvm::StringRef name, MemberAccess access,
+ MethodOptions options, MemberAttributes attrs) {
+ if (name != proc_name || function_decl)
+ return;
+ lldb::AccessType access_type = TranslateMemberAccess(access);
+ bool is_virtual = attrs.isVirtual();
+ bool is_static = attrs.isStatic();
+ bool is_artificial = (options & MethodOptions::CompilerGenerated) ==
+ MethodOptions::CompilerGenerated;
+ function_decl = m_clang.AddMethodToCXXRecordType(
+ parent_ty, proc_name,
+ /*mangled_name=*/nullptr, func_ct, /*access=*/access_type,
+ /*is_virtual=*/is_virtual, /*is_static=*/is_static,
+ /*is_inline=*/false, /*is_explicit=*/false,
+ /*is_attr_used=*/false, /*is_artificial=*/is_artificial);
+ }
+};
+} // namespace
+
static llvm::Optional<PdbCompilandSymId> FindSymbolScope(PdbIndex &index,
PdbCompilandSymId id) {
CVSymbol sym = index.ReadSymbolRecord(id);
@@ -681,7 +745,8 @@ bool PdbAstBuilder::CompleteTagDecl(clang::TagDecl &tag) {
// Visit all members of this class, then perform any finalization necessary
// to complete the class.
CompilerType ct = ToCompilerType(tag_qt);
- UdtRecordCompleter completer(best_ti, ct, tag, *this, m_index);
+ UdtRecordCompleter completer(best_ti, ct, tag, *this, m_index,
+ m_cxx_record_map);
auto error =
llvm::codeview::visitMemberRecordStream(field_list_cvt.data(), completer);
completer.complete();
@@ -1014,8 +1079,62 @@ PdbAstBuilder::GetOrCreateFunctionDecl(PdbCompilandSymId func_id) {
proc_name.consume_front(context_name);
proc_name.consume_front("::");
- clang::FunctionDecl *function_decl = m_clang.CreateFunctionDeclaration(
- parent, OptionalClangModuleID(), proc_name, func_ct, storage, false);
+ clang::FunctionDecl *function_decl = nullptr;
+ if (parent->isRecord()) {
+ clang::QualType parent_qt = llvm::dyn_cast<clang::TypeDecl>(parent)
+ ->getTypeForDecl()
+ ->getCanonicalTypeInternal();
+ lldb::opaque_compiler_type_t parent_opaque_ty =
+ ToCompilerType(parent_qt).GetOpaqueQualType();
+
+ auto iter = m_cxx_record_map.find(parent_opaque_ty);
+ if (iter != m_cxx_record_map.end()) {
+ if (iter->getSecond().contains({proc_name, func_ct})) {
+ return nullptr;
+ }
+ }
+
+ CVType cvt = m_index.tpi().getType(type_id.index);
+ MemberFunctionRecord func_record(static_cast<TypeRecordKind>(cvt.kind()));
+ llvm::cantFail(TypeDeserializer::deserializeAs<MemberFunctionRecord>(
+ cvt, func_record));
+ TypeIndex class_index = func_record.getClassType();
+ CVType parent_cvt = m_index.tpi().getType(class_index);
+ ClassRecord class_record = CVTagRecord::create(parent_cvt).asClass();
+ // If it's a forward reference, try to get the real TypeIndex.
+ if (class_record.isForwardRef()) {
+ llvm::Expected<TypeIndex> eti =
+ m_index.tpi().findFullDeclForForwardRef(class_index);
+ if (eti) {
+ class_record =
+ CVTagRecord::create(m_index.tpi().getType(*eti)).asClass();
+ }
+ }
+ if (!class_record.FieldList.isSimple()) {
+ CVType field_list = m_index.tpi().getType(class_record.FieldList);
+ CreateMethodDecl process(m_index, m_clang, type_id.index, function_decl,
+ parent_opaque_ty, proc_name, func_ct);
+ if (llvm::Error err = visitMemberRecordStream(field_list.data(), process))
+ llvm::consumeError(std::move(err));
+ }
+
+ if (!function_decl) {
+ function_decl = m_clang.AddMethodToCXXRecordType(
+ parent_opaque_ty, proc_name,
+ /*mangled_name=*/nullptr, func_ct,
+ /*access=*/lldb::AccessType::eAccessPublic,
+ /*is_virtual=*/false, /*is_static=*/false,
+ /*is_inline=*/false, /*is_explicit=*/false,
+ /*is_attr_used=*/false, /*is_artificial=*/false);
+ }
+
+ m_cxx_record_map[parent_opaque_ty].insert({proc_name, func_ct});
+ } else {
+ function_decl = m_clang.CreateFunctionDeclaration(
+ parent, OptionalClangModuleID(), proc_name, func_ct, storage, false);
+ CreateFunctionParameters(func_id, *function_decl,
+ func_type->getNumParams());
+ }
lldbassert(m_uid_to_decl.count(toOpaqueUid(func_id)) == 0);
m_uid_to_decl[toOpaqueUid(func_id)] = function_decl;
@@ -1024,8 +1143,6 @@ PdbAstBuilder::GetOrCreateFunctionDecl(PdbCompilandSymId func_id) {
status.uid = toOpaqueUid(func_id);
m_decl_to_status.insert({function_decl, status});
- CreateFunctionParameters(func_id, *function_decl, func_type->getNumParams());
-
return function_decl;
}
@@ -1163,15 +1280,15 @@ clang::QualType PdbAstBuilder::CreateFunctionType(
}
static bool isTagDecl(clang::DeclContext &context) {
- return !!llvm::dyn_cast<clang::TagDecl>(&context);
+ return llvm::isa<clang::TagDecl>(&context);
}
static bool isFunctionDecl(clang::DeclContext &context) {
- return !!llvm::dyn_cast<clang::FunctionDecl>(&context);
+ return llvm::isa<clang::FunctionDecl>(&context);
}
static bool isBlockDecl(clang::DeclContext &context) {
- return !!llvm::dyn_cast<clang::BlockDecl>(&context);
+ return llvm::isa<clang::BlockDecl>(&context);
}
void PdbAstBuilder::ParseAllNamespacesPlusChildrenOf(
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h
index 7bb2584d19a3..73accf5e5e68 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h
@@ -137,6 +137,12 @@ private:
llvm::DenseMap<clang::Decl *, DeclStatus> m_decl_to_status;
llvm::DenseMap<lldb::user_id_t, clang::Decl *> m_uid_to_decl;
llvm::DenseMap<lldb::user_id_t, clang::QualType> m_uid_to_type;
+
+ // From class/struct's opaque_compiler_type_t to a set containing the pairs of
+ // method's name and CompilerType.
+ llvm::DenseMap<lldb::opaque_compiler_type_t,
+ llvm::SmallSet<std::pair<llvm::StringRef, CompilerType>, 8>>
+ m_cxx_record_map;
};
} // namespace npdb
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index bf101ac1acf1..e859b1d5a86c 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -900,7 +900,7 @@ lldb::LanguageType SymbolFileNativePDB::ParseLanguage(CompileUnit &comp_unit) {
return TranslateLanguage(item->m_compile_opts->getLanguage());
}
-void SymbolFileNativePDB::AddSymbols(Symtab &symtab) { return; }
+void SymbolFileNativePDB::AddSymbols(Symtab &symtab) {}
size_t SymbolFileNativePDB::ParseFunctions(CompileUnit &comp_unit) {
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
index c8fb46c75034..d0b27bc5bf79 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
@@ -28,13 +28,15 @@ using namespace lldb_private::npdb;
using Error = llvm::Error;
-UdtRecordCompleter::UdtRecordCompleter(PdbTypeSymId id,
- CompilerType &derived_ct,
- clang::TagDecl &tag_decl,
- PdbAstBuilder &ast_builder,
- PdbIndex &index)
+UdtRecordCompleter::UdtRecordCompleter(
+ PdbTypeSymId id, CompilerType &derived_ct, clang::TagDecl &tag_decl,
+ PdbAstBuilder &ast_builder, PdbIndex &index,
+ llvm::DenseMap<lldb::opaque_compiler_type_t,
+ llvm::SmallSet<std::pair<llvm::StringRef, CompilerType>, 8>>
+ &cxx_record_map)
: m_id(id), m_derived_ct(derived_ct), m_tag_decl(tag_decl),
- m_ast_builder(ast_builder), m_index(index) {
+ m_ast_builder(ast_builder), m_index(index),
+ m_cxx_record_map(cxx_record_map) {
CVType cvt = m_index.tpi().getType(m_id.index);
switch (cvt.kind()) {
case LF_ENUM:
@@ -78,14 +80,24 @@ void UdtRecordCompleter::AddMethod(llvm::StringRef name, TypeIndex type_idx,
clang::QualType method_qt =
m_ast_builder.GetOrCreateType(PdbTypeSymId(type_idx));
m_ast_builder.CompleteType(method_qt);
+ CompilerType method_ct = m_ast_builder.ToCompilerType(method_qt);
+ lldb::opaque_compiler_type_t derived_opaque_ty = m_derived_ct.GetOpaqueQualType();
+ auto iter = m_cxx_record_map.find(derived_opaque_ty);
+ if (iter != m_cxx_record_map.end()) {
+ if (iter->getSecond().contains({name, method_ct})) {
+ return;
+ }
+ }
lldb::AccessType access_type = TranslateMemberAccess(access);
bool is_artificial = (options & MethodOptions::CompilerGenerated) ==
MethodOptions::CompilerGenerated;
m_ast_builder.clang().AddMethodToCXXRecordType(
- m_derived_ct.GetOpaqueQualType(), name.data(), nullptr,
- m_ast_builder.ToCompilerType(method_qt), access_type, attrs.isVirtual(),
- attrs.isStatic(), false, false, false, is_artificial);
+ derived_opaque_ty, name.data(), nullptr, method_ct,
+ access_type, attrs.isVirtual(), attrs.isStatic(), false, false, false,
+ is_artificial);
+
+ m_cxx_record_map[derived_opaque_ty].insert({name, method_ct});
}
Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
index ae7e47c82fe5..9c6b5ed28bc2 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
@@ -54,11 +54,17 @@ class UdtRecordCompleter : public llvm::codeview::TypeVisitorCallbacks {
PdbIndex &m_index;
std::vector<IndexedBase> m_bases;
ClangASTImporter::LayoutInfo m_layout;
+ llvm::DenseMap<lldb::opaque_compiler_type_t,
+ llvm::SmallSet<std::pair<llvm::StringRef, CompilerType>, 8>>
+ &m_cxx_record_map;
public:
- UdtRecordCompleter(PdbTypeSymId id, CompilerType &derived_ct,
- clang::TagDecl &tag_decl, PdbAstBuilder &ast_builder,
- PdbIndex &index);
+ UdtRecordCompleter(
+ PdbTypeSymId id, CompilerType &derived_ct, clang::TagDecl &tag_decl,
+ PdbAstBuilder &ast_builder, PdbIndex &index,
+ llvm::DenseMap<lldb::opaque_compiler_type_t,
+ llvm::SmallSet<std::pair<llvm::StringRef, CompilerType>,
+ 8>> &cxx_record_map);
#define MEMBER_RECORD(EnumName, EnumVal, Name) \
llvm::Error visitKnownMember(llvm::codeview::CVMemberRecord &CVR, \
diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
index db0ae241be7e..a40b6ec9a635 100644
--- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
@@ -239,7 +239,6 @@ void SymbolFilePDB::GetCompileUnitIndex(
}
}
index = UINT32_MAX;
- return;
}
std::unique_ptr<llvm::pdb::PDBSymbolCompiland>
@@ -402,7 +401,7 @@ static size_t ParseFunctionBlocksForPDBSymbol(
block = parent_block;
else
break;
- } else if (llvm::dyn_cast<PDBSymbolBlock>(pdb_symbol)) {
+ } else if (llvm::isa<PDBSymbolBlock>(pdb_symbol)) {
auto uid = pdb_symbol->getSymIndexId();
if (parent_block->FindBlockByID(uid))
break;