From e1ca1e6d0d7ce2c95ddd217c45f430b02ac59c4b Mon Sep 17 00:00:00 2001 From: Yuanfang chen Date: Thu, 2 Jul 2015 18:45:30 -0400 Subject: [PATCH 1/3] Enable generating profile for clang LTO enabled binary. Clang use DW_FORM_ref_addr for DW_AT_abstract_origin when doing LTO. When searching for abstract_origin subprograms, we need to search all CUs. CleanupUnusedSubprograms is disabled because there may be links to it afterwards.(ps: maybe cleanup is needed after parsing of all CUs are done?) --- symbolize/addr2line_inlinestack.cc | 37 ++++++++++++++++++++---------- symbolize/addr2line_inlinestack.h | 1 + 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/symbolize/addr2line_inlinestack.cc b/symbolize/addr2line_inlinestack.cc index ccf5742..1e64eeb 100644 --- a/symbolize/addr2line_inlinestack.cc +++ b/symbolize/addr2line_inlinestack.cc @@ -90,6 +90,17 @@ bool InlineStackHandler::StartSplitCompilationUnit(uint64 offset, return true; } +const SubprogramInfo * +InlineStackHandler::FindSubprogramInfo(uint64 abstract_origin) const { + for (SubprogramsByOffsetMap *sbo : subprograms_by_offset_maps_) { + //printf(" %lld\n", kv.first); + auto I = sbo->find(abstract_origin); + if (I != sbo->end()) + return I->second; + } + return nullptr; +} + void InlineStackHandler::CleanupUnusedSubprograms() { SubprogramsByOffsetMap* subprograms_by_offset = subprograms_by_offset_maps_.back(); @@ -181,7 +192,7 @@ void InlineStackHandler::EndDIE(uint64 offset) { subprogram_stack_.pop_back(); } if (die == DW_TAG_compile_unit && sampled_functions_ != NULL) { - CleanupUnusedSubprograms(); + //CleanupUnusedSubprograms(); } } @@ -247,9 +258,14 @@ void InlineStackHandler::ProcessAttributeUnsigned( subprogram_stack_.back()->set_callsite_discr(data); break; case DW_AT_abstract_origin: - CHECK(form == DW_FORM_ref4); - subprogram_stack_.back()->set_abstract_origin( - compilation_unit_offset_ + data); + CHECK(form == DW_FORM_ref4 || + form == DW_FORM_ref_addr); + if (form == DW_FORM_ref4) { + subprogram_stack_.back()->set_abstract_origin( + compilation_unit_offset_ + data); + } else { + subprogram_stack_.back()->set_abstract_origin(data); + } break; case DW_AT_specification: CHECK(form == DW_FORM_ref4); @@ -547,7 +563,7 @@ const SubprogramInfo *InlineStackHandler::GetDeclaration( } else { uint64 abstract_origin = declaration->abstract_origin(); if (abstract_origin) - declaration = subprograms_by_offset->find(abstract_origin)->second; + declaration = FindSubprogramInfo(abstract_origin); else break; } @@ -557,13 +573,10 @@ const SubprogramInfo *InlineStackHandler::GetDeclaration( const SubprogramInfo *InlineStackHandler::GetAbstractOrigin( const SubprogramInfo *subprog) const { - const int cu_index = subprog->cu_index(); - CHECK(cu_index < subprograms_by_offset_maps_.size()); - SubprogramsByOffsetMap* subprograms_by_offset = - subprograms_by_offset_maps_[cu_index]; - if (subprog->abstract_origin()) - return subprograms_by_offset->find(subprog->abstract_origin())->second; - else + if (subprog->abstract_origin()) { + const SubprogramInfo *info = FindSubprogramInfo(subprog->abstract_origin()); + return info; + } else return subprog; } diff --git a/symbolize/addr2line_inlinestack.h b/symbolize/addr2line_inlinestack.h index 1d7e00a..ae3b677 100644 --- a/symbolize/addr2line_inlinestack.h +++ b/symbolize/addr2line_inlinestack.h @@ -215,6 +215,7 @@ class InlineStackHandler: public Dwarf2Handler { // Cleans up memory consumed by subprograms that are not used. void CleanupUnusedSubprograms(); + const SubprogramInfo *FindSubprogramInfo(uint64 abstract_origin) const; void PopulateSubprogramsByAddress(); From cb8dc4840fd3f06703f1905a19766ffbd83fd376 Mon Sep 17 00:00:00 2001 From: Yuanfang chen Date: Fri, 3 Jul 2015 17:18:02 -0400 Subject: [PATCH 2/3] [Bugfix] Size of DW_FORM_ref_addr in both DWARF2 and DWARF3 are both offset size According to http://wiki.dwarfstd.org/index.php?title=DWARF_FAQ#How_big_is_a_DW_FORM_ref_addr.3F --- symbolize/dwarf2reader.cc | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/symbolize/dwarf2reader.cc b/symbolize/dwarf2reader.cc index 897d684..19ca385 100644 --- a/symbolize/dwarf2reader.cc +++ b/symbolize/dwarf2reader.cc @@ -224,14 +224,11 @@ const char* CompilationUnit::SkipAttribute(const char* start, break; case DW_FORM_ref_addr: // DWARF2 and 3 differ on whether ref_addr is address size or - // offset size. - if (header_.version == 2) { - return start + reader_->AddressSize(); - } else { - return start + reader_->OffsetSize(); - } + // offset size according to respective standard. + // BUT, per http://wiki.dwarfstd.org/index.php?title=DWARF_FAQ#How_big_is_a_DW_FORM_ref_addr.3F + // it is a bug in DWARF2 standard, so they are both offset. + return start + reader_->OffsetSize(); break; - case DW_FORM_block1: return start + 1 + reader_->ReadOneByte(start); break; From f58e8e9b7749dd05df6aeca05b9b786d9e5e8fac Mon Sep 17 00:00:00 2001 From: Yuanfang chen Date: Tue, 7 Jul 2015 10:19:46 -0400 Subject: [PATCH 3/3] [Bugfix] Inlined function has offsets relative to first line of file in llvm profile output. For top level symbols, their start_line in SymbolMap are alwarys 0, since in SymbolMap::AddSourceCount top level symbol do not take the value from SourceStack. For Inlined symbols, their start_line in SymbolMap are assigned in SymbolMap::TraverseInlineStack. Fix by assign correct start_line to top level symbols and change LLVMSourceProfileWriter::WriteSourceLocation accordingly. --- llvm_profile_writer.cc | 8 ++++---- symbol_map.cc | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/llvm_profile_writer.cc b/llvm_profile_writer.cc index ea1165b..385106c 100644 --- a/llvm_profile_writer.cc +++ b/llvm_profile_writer.cc @@ -39,11 +39,11 @@ class LLVMSourceProfileWriter : public SymbolTraverser { } protected: - void WriteSourceLocation(uint32 start_line, uint32 offset) { + void WriteSourceLocation(uint32 offset) { if (offset & 0xffff) { - fprintf(outf_, "%u.%u: ", (offset >> 16) + start_line, offset & 0xffff); + fprintf(outf_, "%u.%u: ", offset >> 16, offset & 0xffff); } else { - fprintf(outf_, "%u: ", (offset >> 16) + start_line); + fprintf(outf_, "%u: ", offset >> 16); } } @@ -78,7 +78,7 @@ class LLVMSourceProfileWriter : public SymbolTraverser { for (const auto &pos : positions) { PositionCountMap::const_iterator ret = node->pos_counts.find(pos); DCHECK(ret != node->pos_counts.end()); - WriteSourceLocation(node->info.start_line, pos); + WriteSourceLocation(pos); fprintf(outf_, "%llu", ret->second.count); // If there is a call at this location, emit the possible diff --git a/symbol_map.cc b/symbol_map.cc index 495d2e4..995df6a 100644 --- a/symbol_map.cc +++ b/symbol_map.cc @@ -361,6 +361,7 @@ void SymbolMap::AddSourceCount(const string &symbol_name, return; } Symbol *symbol = TraverseInlineStack(symbol_name, src, count); + symbol->info.start_line = src[0].start_line; if (op == MAX) { if (count > symbol->pos_counts[src[0].Offset()].count) { symbol->pos_counts[src[0].Offset()].count = count;