Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions addr2line.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/Object/Binary.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Error.h"

ABSL_RETIRED_FLAG(bool, use_legacy_symbolizer, false,
"whether to use google3 symbolizer");
Expand Down Expand Up @@ -87,8 +88,29 @@ void LLVMAddr2line::GetInlineStack(uint64_t address, SourceStack *stack) const {
llvm::SmallVector<llvm::DWARFDie, 4> InlinedChain;
cu_iter->second->getInlinedChainForAddress(address, InlinedChain);

uint32_t row_index = line_table->lookupAddress(
{address, llvm::object::SectionedAddress::UndefSection});
uint64_t section_index = llvm::object::SectionedAddress::UndefSection;
if (IsKernelModule(getObject()->getFileName())) {
// For kernel modules (relocatable objects), line table sequences are often
// tied to their actual section. We must provide the actual section index
// (instead of the UndefSection wildcard) to lookupAddress, otherwise it
// will fail to match sequences that are not marked as UndefSection. We
// only focus on the .text section to be consistent with symbol_map.cc.
for (const auto& sec : getObject()->sections()) {
auto name = sec.getName();
if (!name) {
llvm::consumeError(name.takeError());
continue;
}
if (*name == ".text") {
if (address >= sec.getAddress() &&
address < sec.getAddress() + sec.getSize()) {
section_index = sec.getIndex();
}
break;
}
}
}
uint32_t row_index = line_table->lookupAddress({address, section_index});
uint32_t file = (row_index == -1U ? -1U : line_table->Rows[row_index].File);
uint32_t line = (row_index == -1U ? 0 : line_table->Rows[row_index].Line);
uint32_t discriminator =
Expand Down
6 changes: 6 additions & 0 deletions addr2line.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include "base/integral_types.h"
#include "source_info.h"
#include "third_party/abseil/absl/strings/match.h"
#include "third_party/abseil/absl/strings/string_view.h"

#if defined(HAVE_LLVM)
Expand Down Expand Up @@ -89,6 +90,11 @@ class Google3Addr2line : public Addr2line {
DISALLOW_COPY_AND_ASSIGN(Google3Addr2line);
};
#endif

inline bool IsKernelModule(absl::string_view path) {
return absl::EndsWith(path, ".ko");
}

} // namespace devtools_crosstool_autofdo

#endif // AUTOFDO_ADDR2LINE_H_
12 changes: 12 additions & 0 deletions symbol_map.cc
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,18 @@ void SymbolMap::ReadLoadableExecSegmentInfo(bool is_kernel) {
<< " vaddr=" << info.vaddr;
}
}

if (si_vec.empty() && IsKernelModule(binary_)) {
// For kernel modules without program headers, we simulate a loadable
// executable segment by using the file offset and link-time address of the
// .text section. We focus on .text and ignore other executable sections
// like .init.text and .exit.text as they are not important for steady-state
// performance.
ElfReader::SectionInfo info;
if (elf_reader.GetSectionInfoByName(".text", &info) != nullptr) {
add_loadable_exec_segment(info.offset, info.addr);
}
}
}

void SymbolMap::BuildSymbolMap() {
Expand Down
17 changes: 17 additions & 0 deletions symbol_map_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "base/logging.h"
#include "llvm_profile_reader.h"
#include "source_info.h"
#include "util/symbolize/elf_reader.h"
#include "gtest/gtest.h"
#include "third_party/abseil/absl/container/node_hash_set.h"
#include "third_party/abseil/absl/flags/flag.h"
Expand Down Expand Up @@ -524,4 +525,20 @@ TEST(AddressConversion, OffsetToVaddr) {
EXPECT_EQ(symbol_map.GetFileOffsetFromStaticVaddr(0x001010), 0x002010);
}

TEST(AddressConversion, KernelModuleFakeSegment) {
SymbolMap symbol_map(absl::StrCat(testing::SrcDir(), kTestDataDir,
"test_kernel_module.ko"));
symbol_map.ReadLoadableExecSegmentInfo(/*is_kernel=*/false);

// Use ElfReader to get the actual .text section info from the test file.
devtools_crosstool_autofdo::ElfReader elf_reader(
absl::StrCat(testing::SrcDir(), kTestDataDir, "test_kernel_module.ko"));
devtools_crosstool_autofdo::ElfReader::SectionInfo info;
ASSERT_TRUE(elf_reader.GetSectionInfoByName(".text", &info) != nullptr);

// Verify that the fake segment maps the file offset to the address correctly.
EXPECT_EQ(symbol_map.GetFileOffsetFromStaticVaddr(info.addr), info.offset);
EXPECT_EQ(symbol_map.get_static_vaddr(info.offset), info.addr);
}

} // namespace
Binary file added testdata/test_kernel_module.ko
Binary file not shown.
Loading
Loading