diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ffc536..b300f00 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,8 +21,12 @@ endfunction() function (build_gcov) add_subdirectory(third_party/abseil) add_subdirectory(third_party/glog) + add_subdirectory(third_party/googletest) add_custom_target(exclude_extlib_tests ALL + COMMAND rm -f ${gtest_BINARY_DIR}/CTestTestfile.cmake + COMMAND rm -f ${gmock_BINARY_DIR}/CTestTestfile.cmake + COMMAND rm -f ${googletest-distribution_BINARY_DIR}/CTestTestfile.cmake COMMAND rm -f ${glog_BINARY_DIR}/CTestTestfile.cmake COMMAND rm -f ${absl_BINARY_DIR}/CTestTestfile.cmake) @@ -31,6 +35,8 @@ function (build_gcov) third_party/abseil third_party/perf_data_converter/src third_party/perf_data_converter/src/quipper + third_party/googletest/googletest/include + third_party/googletest/googlemock/include util ${PROJECT_BINARY_DIR} ${PROJECT_BINARY_DIR}/third_party/glog @@ -39,23 +45,26 @@ function (build_gcov) find_library (LIBELF_LIBRARIES NAMES elf REQUIRED) find_library (LIBCRYPTO_LIBRARIES NAMES crypto REQUIRED) + add_library(addr2line_lib OBJECT + legacy_addr2line.cc + util/symbolize/addr2line_inlinestack.cc + util/symbolize/bytereader.cc + util/symbolize/functioninfo.cc + util/symbolize/dwarf2reader.cc + util/symbolize/dwarf3ranges.cc + util/symbolize/elf_reader.cc + util/symbolize/index_helper.cc + ) + add_library(create_gcov_lib OBJECT create_gcov.cc gcov.cc instruction_map.cc - legacy_addr2line.cc profile.cc profile_creator.cc profile_writer.cc sample_reader.cc symbol_map.cc - util/symbolize/addr2line_inlinestack.cc - util/symbolize/bytereader.cc - util/symbolize/functioninfo.cc - util/symbolize/dwarf2reader.cc - util/symbolize/dwarf3ranges.cc - util/symbolize/elf_reader.cc - util/symbolize/index_helper.cc ) target_link_libraries(create_gcov_lib perf_proto) @@ -94,6 +103,7 @@ function (build_gcov) absl::flags absl::flags_parse create_gcov_lib + addr2line_lib glog quipper_perf ) @@ -136,6 +146,24 @@ function (build_gcov) dump_gcov_lib glog) + add_executable(addr2line_test addr2line_test.cc) + target_link_libraries(addr2line_test + absl::base + gtest + gtest_main + absl::flags + absl::flags_parse + addr2line_lib + glog + quipper_perf) + add_test(NAME addr2line_test COMMAND addr2line_test) + + add_custom_command(PRE_BUILD + OUTPUT prepare_cmds + COMMAND ln -s -f ${CMAKE_HOME_DIRECTORY}/testdata) + add_custom_target(prepare ALL + DEPENDS prepare_cmds) + endfunction() function (build_llvm) diff --git a/addr2line_test.cc b/addr2line_test.cc new file mode 100644 index 0000000..59a666a --- /dev/null +++ b/addr2line_test.cc @@ -0,0 +1,18 @@ +#include "addr2line.h" +#include "third_party/abseil/absl/strings/str_cat.h" +#include "util/testing/status_matchers.h" + +namespace { + +using ::devtools_crosstool_autofdo::Addr2line; + +TEST(Addr2lineTest, Dwarf2Dwarf5Binary) { + const std::string binary = + absl::StrCat(::testing::SrcDir(), + "/testdata/" + "dwarf2_dwarf5.bin"); + + Addr2line* addr2line = Addr2line::Create(binary); + EXPECT_TRUE(addr2line != NULL); +} +} // namespace diff --git a/legacy_addr2line.cc b/legacy_addr2line.cc index 6ceb41d..f19c1b1 100644 --- a/legacy_addr2line.cc +++ b/legacy_addr2line.cc @@ -105,27 +105,28 @@ bool Google3Addr2line::Prepare() { size_t debug_info_size = 0; size_t debug_addr_size = 0; size_t debug_ranges_size = 0; + size_t debug_rnglists_size = 0; const char *debug_info_data = NULL; const char *debug_addr_data = NULL; const char *debug_ranges_data = NULL; + const char *debug_rnglists_data = NULL; bool is_rnglists_section = false; GetSection(sections, ".debug_info", &debug_info_data, &debug_info_size); if (debug_info_data == NULL) LOG(WARNING) << "File '" << binary_name_ << "' does not have .debug_info section."; GetSection(sections, ".debug_addr", &debug_addr_data, &debug_addr_size); GetSection(sections, ".debug_ranges", &debug_ranges_data, &debug_ranges_size); - if (debug_ranges_data == NULL) { - GetSection(sections, ".debug_rnglists", &debug_ranges_data, &debug_ranges_size); - if (debug_ranges_data != NULL) - is_rnglists_section = true; - else - LOG(WARNING) << "File '" << binary_name_ << "' does not have .debug_ranges nor .debug_rnglists sections."; + GetSection(sections, ".debug_rnglists", &debug_rnglists_data, &debug_rnglists_size); + + if (debug_ranges_data == NULL && debug_rnglists_data == NULL) { + LOG(WARNING) << "File '" << binary_name_ << "' does not have .debug_ranges nor .debug_rnglists sections."; } AddressRangeList debug_ranges(debug_ranges_data, debug_ranges_size, + debug_rnglists_data, + debug_rnglists_size, &reader, - is_rnglists_section, debug_addr_data, debug_addr_size); inline_stack_handler_ = new InlineStackHandler( diff --git a/testdata/dwarf2_dwarf5.bin b/testdata/dwarf2_dwarf5.bin new file mode 100644 index 0000000..62427a9 Binary files /dev/null and b/testdata/dwarf2_dwarf5.bin differ diff --git a/util/symbolize/addr2line_inlinestack.cc b/util/symbolize/addr2line_inlinestack.cc index 6e3a342..f68f6e1 100644 --- a/util/symbolize/addr2line_inlinestack.cc +++ b/util/symbolize/addr2line_inlinestack.cc @@ -99,7 +99,7 @@ bool InlineStackHandler::StartCompilationUnit(uint64 offset, uint8 /*address_size*/, uint8 /*offset_size*/, uint64 /*cu_length*/, - uint8 /*dwarf_version*/) { + uint8 dwarf_version) { CHECK(subprogram_stack_.empty()); compilation_unit_offset_ = offset; compilation_unit_base_ = 0; @@ -109,6 +109,7 @@ bool InlineStackHandler::StartCompilationUnit(uint64 offset, input_file_index_ = 0; subprograms_by_offset_maps_.push_back(new SubprogramsByOffsetMap); } + dwarf_version_ = dwarf_version; return true; } @@ -348,13 +349,14 @@ void InlineStackHandler::ProcessAttributeUnsigned( case DW_AT_ranges: { CHECK_EQ(0, subprogram_stack_.back()->address_ranges()->size()); AddressRangeList::RangeList ranges; - if (form == DW_FORM_sec_offset) { - address_ranges_->ReadRangeList(data, compilation_unit_base_, &ranges); + + if (form == DW_FORM_sec_offset || form == DW_FORM_data4 || form == DW_FORM_data8) { + address_ranges_->ReadRangeList(data, compilation_unit_base_, &ranges, dwarf_version_); } else { - CHECK(form == DW_FORM_rnglistx); - uint64 address_ = address_ranges_->GetRngListsElementOffsetByIndex(ranges_base_, data); - address_ranges_->ReadDwarfRngListwithOffsetArray(address_, compilation_unit_base_, &ranges, addr_base_, ranges_base_); + CHECK(form == DW_FORM_rnglistx); + uint64 address_ = address_ranges_->GetRngListsElementOffsetByIndex(ranges_base_, data); + address_ranges_->ReadDwarfRngListwithOffsetArray(address_, compilation_unit_base_, &ranges, addr_base_, ranges_base_); } if (subprogram_stack_.size() == 1) { @@ -440,7 +442,7 @@ void InlineStackHandler::ProcessAttributeUnsigned( str_offset_base_ = data; break; case DW_AT_ranges: - CHECK(form == DW_FORM_sec_offset); + CHECK(form == DW_FORM_sec_offset || form == DW_FORM_data4 || form == DW_FORM_data8); FALLTHROUGH_INTENDED; case DW_AT_GNU_ranges_base: case DW_AT_rnglists_base: diff --git a/util/symbolize/addr2line_inlinestack.h b/util/symbolize/addr2line_inlinestack.h index 751846f..0bf46cc 100644 --- a/util/symbolize/addr2line_inlinestack.h +++ b/util/symbolize/addr2line_inlinestack.h @@ -282,6 +282,7 @@ class InlineStackHandler: public Dwarf2Handler { int overlap_count_; bool have_two_level_line_tables_; bool subprogram_added_by_cu_; + uint8 dwarf_version_; DISALLOW_COPY_AND_ASSIGN(InlineStackHandler); }; diff --git a/util/symbolize/dwarf2reader.cc b/util/symbolize/dwarf2reader.cc index fb82d36..072665f 100644 --- a/util/symbolize/dwarf2reader.cc +++ b/util/symbolize/dwarf2reader.cc @@ -1017,15 +1017,17 @@ void CompilationUnit::ProcessSplitDwarf() { auto iter = sections.find(".debug_rnglists"); size_t debug_ranges_size = 0; const char *debug_ranges_data = NULL; + size_t debug_rnglist_size = 0; + const char *debug_rnglist_data = NULL; if (iter != sections.end()) { - debug_ranges_data = iter->second.first; - debug_ranges_size = iter->second.second; - const bool is_rnglists_section = true; + debug_rnglist_data = iter->second.first; + debug_rnglist_size = iter->second.second; AddressRangeList *debug_ranges = new AddressRangeList(debug_ranges_data, debug_ranges_size, + debug_rnglist_data, + debug_rnglist_size, &reader, - is_rnglists_section, addr_buffer_, addr_buffer_length_); InlineStackHandler *inlinestackhandler = dynamic_cast(handler_); diff --git a/util/symbolize/dwarf3ranges.cc b/util/symbolize/dwarf3ranges.cc index 565d07c..13f5a9a 100644 --- a/util/symbolize/dwarf3ranges.cc +++ b/util/symbolize/dwarf3ranges.cc @@ -21,9 +21,9 @@ namespace devtools_crosstool_autofdo { void AddressRangeList::ReadRangeList(uint64 offset, uint64 base, - AddressRangeList::RangeList* ranges, uint64 addr_base) { + AddressRangeList::RangeList* ranges, uint8 dwarf_version, uint64 addr_base) { - if (is_rnglists_section) { + if (dwarf_version >= 5) { ReadDwarfRngListsDirectly(offset, base, ranges, addr_base); } else { @@ -34,7 +34,7 @@ void AddressRangeList::ReadRangeList(uint64 offset, uint64 base, void AddressRangeList::ReadDwarfRangeList(uint64 offset, uint64 base, AddressRangeList::RangeList* ranges) { - CHECK(!is_rnglists_section); + CHECK(ranges_buffer_ != NULL); uint8 width = reader_->AddressSize(); uint64 largest_address; @@ -45,9 +45,9 @@ void AddressRangeList::ReadDwarfRangeList(uint64 offset, uint64 base, else LOG(FATAL) << "width==" << width << " must be 4 or 8"; - const char* pos = buffer_ + offset; + const char* pos = ranges_buffer_ + offset; do { - CHECK((pos + 2*width) <= buffer_ + buffer_length_); + CHECK((pos + 2*width) <= ranges_buffer_ + ranges_buffer_length_); uint64 start = reader_->ReadAddress(pos); uint64 stop = reader_->ReadAddress(pos+width); if (start == largest_address) @@ -71,7 +71,7 @@ void AddressRangeList::ReadDwarfRngListsDirectly(uint64 offset, uint64 base, // (The address size is equal for all elements.) auto i = rngdatamap_.begin(); CHECK(i != rngdatamap_.end()); - ReadDwarfRngLists(base, ranges, buffer_ + offset, addr_base, i->second.address_size); + ReadDwarfRngLists(base, ranges, rnglist_buffer_ + offset, addr_base, i->second.address_size); } void AddressRangeList::ReadDwarfRngListwithOffsetArray(uint64 offset, uint64 base, @@ -79,7 +79,7 @@ void AddressRangeList::ReadDwarfRngListwithOffsetArray(uint64 offset, uint64 bas auto i = rngdatamap_.find(range_base_); CHECK(i != rngdatamap_.end()); RngListsData& rnglistsdata = i->second; - ReadDwarfRngLists(base, ranges, buffer_ + rnglistsdata.rnglist_base_ + offset, addr_base, rnglistsdata.address_size); + ReadDwarfRngLists(base, ranges, rnglist_buffer_ + rnglistsdata.rnglist_base_ + offset, addr_base, rnglistsdata.address_size); } void AddressRangeList::ReadDwarfRngLists(uint64 base, @@ -87,12 +87,12 @@ void AddressRangeList::ReadDwarfRngLists(uint64 base, const char* pos, uint64 addr_base, uint8 address_size) { - CHECK(is_rnglists_section); + CHECK(rnglist_buffer_ != NULL); bool read_next_entry = true; do { - CHECK(pos < buffer_ + buffer_length_); + CHECK(pos < rnglist_buffer_ + rnglist_buffer_length_); uint8 entry_kind = reader_->ReadOneByte(pos); pos += 1; switch (entry_kind) { @@ -112,13 +112,13 @@ void AddressRangeList::ReadDwarfRngLists(uint64 base, size_t len = 0; // Start uint64 start_index = reader_->ReadUnsignedLEB128(pos, &len); pos += len; - CHECK(pos <= buffer_ + buffer_length_); + CHECK(pos <= rnglist_buffer_ + rnglist_buffer_length_); const char* start_ptr = addr_buffer_ + addr_base + start_index * reader_->AddressSize(); CHECK(start_ptr <= (addr_buffer_ + addr_buffer_length_)); uint64 start = reader_->ReadAddress(start_ptr); // Stop uint64 stop_index = reader_->ReadUnsignedLEB128(pos, &len); pos += len; - CHECK(pos <= buffer_ + buffer_length_); + CHECK(pos <= rnglist_buffer_ + rnglist_buffer_length_); const char* stop_ptr = addr_buffer_ + addr_base + stop_index * reader_->AddressSize(); CHECK(stop_ptr <= (addr_buffer_ + addr_buffer_length_)); uint64 stop = reader_->ReadAddress(stop_ptr); @@ -130,13 +130,13 @@ void AddressRangeList::ReadDwarfRngLists(uint64 base, size_t len = 0; // Start uint64 start_index = reader_->ReadUnsignedLEB128(pos, &len); pos += len; - CHECK(pos <= buffer_ + buffer_length_); + CHECK(pos <= rnglist_buffer_ + rnglist_buffer_length_); const char* start_ptr = addr_buffer_ + addr_base + start_index * reader_->AddressSize(); CHECK(start_ptr <= (addr_buffer_ + addr_buffer_length_)); uint64 start = reader_->ReadAddress(start_ptr); // Length uint64 range_length = reader_->ReadUnsignedLEB128(pos, &len); pos += len; - CHECK(pos <= buffer_ + buffer_length_); + CHECK(pos <= rnglist_buffer_ + rnglist_buffer_length_); if (range_length != 0) ranges->push_back (make_pair (start + base, start + base + range_length)); break; @@ -144,23 +144,23 @@ void AddressRangeList::ReadDwarfRngLists(uint64 base, case DW_RLE_offset_pair: { size_t len = 0; uint64 start = reader_->ReadUnsignedLEB128(pos, &len); pos += len; - CHECK(pos <= buffer_ + buffer_length_); + CHECK(pos <= rnglist_buffer_ + rnglist_buffer_length_); uint64 stop = reader_->ReadUnsignedLEB128(pos, &len); pos += len; - CHECK(pos <= buffer_ + buffer_length_); + CHECK(pos <= rnglist_buffer_ + rnglist_buffer_length_); if (start != stop) ranges->push_back (make_pair (start + base, stop + base)); break; } case DW_RLE_base_address: { - CHECK(pos + address_size <= buffer_ + buffer_length_); + CHECK(pos + address_size <= rnglist_buffer_ + rnglist_buffer_length_); base = reader_->ReadAddress(pos); pos += address_size; break; case DW_RLE_start_end: size_t len = 0; uint64 start = reader_->ReadAddress(pos); pos += address_size; - CHECK(pos <= buffer_ + buffer_length_); + CHECK(pos <= rnglist_buffer_ + rnglist_buffer_length_); uint64 stop = reader_->ReadAddress(pos); pos += address_size; - CHECK(pos <= buffer_ + buffer_length_); + CHECK(pos <= rnglist_buffer_ + rnglist_buffer_length_); if (start != stop) ranges->push_back (make_pair (start, stop)); break; @@ -168,10 +168,10 @@ void AddressRangeList::ReadDwarfRngLists(uint64 base, case DW_RLE_start_length: { size_t len = 0; uint64 start = reader_->ReadAddress(pos); pos += address_size; - CHECK(pos <= buffer_ + buffer_length_); + CHECK(pos <= rnglist_buffer_ + rnglist_buffer_length_); // Length uint64 range_length = reader_->ReadUnsignedLEB128(pos, &len); pos += len; - CHECK(pos <= buffer_ + buffer_length_); + CHECK(pos <= rnglist_buffer_ + rnglist_buffer_length_); if (range_length != 0) ranges->push_back (make_pair (base + start, base + start + range_length)); break; @@ -185,41 +185,41 @@ void AddressRangeList::ReadDwarfRngLists(uint64 base, } void AddressRangeList::ReadDwarfRngListsHeader() { - CHECK(is_rnglists_section); + CHECK(rnglist_buffer_ != NULL); - const char* ptr = buffer_; + const char* ptr = rnglist_buffer_; do { const char* section_start_ptr = ptr; RngListsData rnglistsdata; - CHECK(ptr + 12 < buffer_ + buffer_length_); + CHECK(ptr + 12 < rnglist_buffer_ + rnglist_buffer_length_); // unit_length (initial length) size_t unit_length_size; rnglistsdata.unit_length = reader_->ReadInitialLength(ptr, &unit_length_size); - CHECK(unit_length_size + rnglistsdata.unit_length <= buffer_length_); + CHECK(unit_length_size + rnglistsdata.unit_length <= rnglist_buffer_length_); ptr += unit_length_size; - CHECK(ptr + 2 < buffer_ + buffer_length_); + CHECK(ptr + 2 < rnglist_buffer_ + rnglist_buffer_length_); rnglistsdata.version = reader_->ReadTwoBytes(ptr); CHECK(rnglistsdata.version == 5); ptr += 2; - CHECK(ptr + 1 < buffer_ + buffer_length_); + CHECK(ptr + 1 < rnglist_buffer_ + rnglist_buffer_length_); rnglistsdata.address_size = reader_->ReadOneByte(ptr); ptr += 1; - CHECK(ptr + 1 < buffer_ + buffer_length_); + CHECK(ptr + 1 < rnglist_buffer_ + rnglist_buffer_length_); rnglistsdata.segment_selector_size = reader_->ReadOneByte(ptr); ptr += 1; - CHECK(ptr + 4 < buffer_ + buffer_length_); + CHECK(ptr + 4 < rnglist_buffer_ + rnglist_buffer_length_); rnglistsdata.offset_entry_count = reader_->ReadFourBytes(ptr); ptr += 4; - rnglistsdata.rnglist_base_ = ptr - buffer_; + rnglistsdata.rnglist_base_ = ptr - rnglist_buffer_; if(rnglistsdata.offset_entry_count != 0) { for(int i = 0; i < rnglistsdata.offset_entry_count; ++i) { @@ -231,7 +231,7 @@ void AddressRangeList::ReadDwarfRngListsHeader() { // Jump to next header inside .debug_rnglists ptr = section_start_ptr + (rnglistsdata.unit_length + unit_length_size); - } while(ptr < buffer_ + buffer_length_); + } while(ptr < rnglist_buffer_ + rnglist_buffer_length_); } @@ -249,7 +249,7 @@ uint64 AddressRangeList::GetRngListsElementOffsetByIndex(uint64 range_base, uint uint64 AddressRangeList::ReadOffset(const char** offsetarrayptr) { - CHECK(*offsetarrayptr + reader_->OffsetSize() < buffer_ + buffer_length_); + CHECK(*offsetarrayptr + reader_->OffsetSize() < rnglist_buffer_ + rnglist_buffer_length_); uint64 offset = reader_->ReadOffset(*offsetarrayptr); *offsetarrayptr = *offsetarrayptr + reader_->OffsetSize(); return offset; diff --git a/util/symbolize/dwarf3ranges.h b/util/symbolize/dwarf3ranges.h index 45abfe3..fc0299c 100644 --- a/util/symbolize/dwarf3ranges.h +++ b/util/symbolize/dwarf3ranges.h @@ -68,35 +68,37 @@ class AddressRangeList { typedef pair Range; typedef vector RangeList; typedef std::map RngDataMap; - AddressRangeList(const char* buffer, - uint64 buffer_length, + AddressRangeList(const char* ranges_buffer, + uint64 ranges_buffer_length, + const char* rnglist_buffer, + uint64 rnglist_buffer_length, ByteReader* reader, - bool is_rnglists_section, const char* addr_buffer, uint64 addr_buffer_length) : reader_(reader), - buffer_(buffer), - buffer_length_(buffer_length), - is_rnglists_section(is_rnglists_section), + ranges_buffer_(ranges_buffer), + ranges_buffer_length_(ranges_buffer_length), + rnglist_buffer_(rnglist_buffer), + rnglist_buffer_length_(rnglist_buffer_length), addr_buffer_(addr_buffer), addr_buffer_length_(addr_buffer_length), rngdatamap_() { - if (is_rnglists_section) { + if (rnglist_buffer != NULL) { ReadDwarfRngListsHeader(); } } void ReadRangeList(uint64 offset, uint64 base, - RangeList* output, uint64 addr_base = 0); + RangeList* output, uint8 dwarf_version, uint64 addr_base = 0); // This handles the case where we read ranges with DW_FORM_sec_offset. - // In this case, the buffer does not have offset array. So for calculating the position, - // we only add the offset to buffer_. + // In this case, the rnglist_buffer_ does not have offset array. So for calculating the position, + // we only add the offset to rnglist_buffer_. void ReadDwarfRngListsDirectly(uint64 offset, uint64 base, AddressRangeList::RangeList* ranges, uint64 addr_base); - // In this case DW_FORM_rnglistx, buffer_ includes offset array too. - // So we have to add that to the the buffer_ to be able to read the RngLists. + // In this case DW_FORM_rnglistx, rnglist_buffer_ includes offset array too. + // So we have to add that to the the rnglist_buffer_ to be able to read the RngLists. void ReadDwarfRngListwithOffsetArray(uint64 offset, uint64 base, AddressRangeList::RangeList* ranges, uint64 addr_base, uint64 range_base_); @@ -114,10 +116,6 @@ class AddressRangeList { return result; } - bool IsRngListsSection() { - return is_rnglists_section; - } - uint64 GetRngListsElementOffsetByIndex(uint64 addr_base, uint64 rng_index); private: @@ -136,12 +134,12 @@ class AddressRangeList { // The associated ByteReader that handles endianness issues for us ByteReader* reader_; - // buffer is the buffer for our range info - const char* buffer_; - uint64 buffer_length_; + const char* ranges_buffer_; + uint64 ranges_buffer_length_; + const char* rnglist_buffer_; + uint64 rnglist_buffer_length_; const char* addr_buffer_; uint64 addr_buffer_length_; - bool is_rnglists_section; // a map of addr_base_ -> RngListsData // If the RngList we are processing does not have offset array,