Skip to content

Commit

Permalink
DWARF processing fixes (#224)
Browse files Browse the repository at this point in the history
Add support for binaries with both .debug_ranges and .debug_rnglists sections.

.debug_rnglists was added in DWARF5 to replace .debug_ranges. This change
handles cases when the binary has compilation units with DWARF5 info and
compilation units with pre-version-5 DWARF info.

Fix processing of DW_AT_ranges attributes to allow DW_FORM_data4 and DW_FORM_data8
This affects DWARF pre-version-4 and was broken by
dd1395a .

This patch also adds a test with a binary from #154 .

Fixes #154
  • Loading branch information
erozenfeld authored Aug 16, 2024
1 parent 79a581d commit 4f0fcef
Show file tree
Hide file tree
Showing 9 changed files with 127 additions and 77 deletions.
44 changes: 36 additions & 8 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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
Expand All @@ -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)

Expand Down Expand Up @@ -94,6 +103,7 @@ function (build_gcov)
absl::flags
absl::flags_parse
create_gcov_lib
addr2line_lib
glog
quipper_perf
)
Expand Down Expand Up @@ -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)
Expand Down
18 changes: 18 additions & 0 deletions addr2line_test.cc
Original file line number Diff line number Diff line change
@@ -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
15 changes: 8 additions & 7 deletions legacy_addr2line.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Binary file added testdata/dwarf2_dwarf5.bin
Binary file not shown.
16 changes: 9 additions & 7 deletions util/symbolize/addr2line_inlinestack.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions util/symbolize/addr2line_inlinestack.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};
Expand Down
10 changes: 6 additions & 4 deletions util/symbolize/dwarf2reader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<InlineStackHandler*>(handler_);
Expand Down
Loading

0 comments on commit 4f0fcef

Please sign in to comment.