Commit 0f0fe916 authored by Robin Cheng's avatar Robin Cheng Committed by Facebook GitHub Bot

Make SymbolizerTest pass if compiled as PIE.

Summary:
The symbolizer takes mapped addresses (address listed in ELF, offset by the binary offset (which is zero for non-PIE)) and symbolizes it into non-mapped addresses. In a couple of places in SymbolizerTest, we took the non-mapped addresses and symbolized them again, which wouldn't work if the binary was compiled with PIE. In another place in SymbolizerTest, the mapped address was used to look up DWARF information, whereas we needed the non-mapped address. This diff addresses these issues.

Additionally, I discovered that r_debug::r_map->l_addr is the "right" way to get the PIE offset, so this diff pulls that common functionality to symbolizer/detail/Debug.h and use it for Symbolizer and the three tests so far that need PIE relocation adjustments.

Reviewed By: yfeldblum

Differential Revision: D23492850

fbshipit-source-id: 62353e576c50b44070b323b5477fea9bb4c0b500
parent e653781c
......@@ -30,6 +30,7 @@
#include <folly/experimental/symbolizer/Elf.h>
#include <folly/experimental/symbolizer/ElfCache.h>
#include <folly/experimental/symbolizer/LineReader.h>
#include <folly/experimental/symbolizer/detail/Debug.h>
#include <folly/lang/SafeAssert.h>
#include <folly/portability/Config.h>
#include <folly/portability/SysMman.h>
......@@ -49,25 +50,6 @@
#include <execinfo.h>
#endif
#if FOLLY_HAVE_ELF
#include <link.h>
#endif
#if defined(__linux__) && FOLLY_HAVE_ELF && FOLLY_HAVE_DWARF
FOLLY_MAYBE_UNUSED static struct r_debug* get_r_debug() {
return &_r_debug;
}
#elif defined(__APPLE__)
extern struct r_debug _r_debug;
FOLLY_MAYBE_UNUSED static struct r_debug* get_r_debug() {
return &_r_debug;
}
#else
FOLLY_MAYBE_UNUSED static struct r_debug* get_r_debug() {
return nullptr;
}
#endif
namespace folly {
namespace symbolizer {
......@@ -105,7 +87,7 @@ void setSymbolizedFrame(
} // namespace
bool Symbolizer::isAvailable() {
return get_r_debug();
return detail::get_r_debug();
}
Symbolizer::Symbolizer(
......@@ -126,7 +108,7 @@ size_t Symbolizer::symbolize(
FOLLY_SAFE_CHECK(addrCount <= frameCount, "Not enough frames.");
size_t remaining = addrCount;
auto const dbg = get_r_debug();
auto const dbg = detail::get_r_debug();
if (dbg == nullptr) {
return 0;
}
......
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <folly/CppAttributes.h>
#if FOLLY_HAVE_ELF
#include <link.h>
#endif
namespace folly {
namespace symbolizer {
namespace detail {
#if defined(__linux__) && FOLLY_HAVE_ELF && FOLLY_HAVE_DWARF
inline struct r_debug* get_r_debug() {
return &_r_debug;
}
#elif defined(__APPLE__)
extern struct r_debug _r_debug;
inline struct r_debug* get_r_debug() {
return &_r_debug;
}
#else
inline struct r_debug* get_r_debug() {
return nullptr;
}
#endif
} // namespace detail
} // namespace symbolizer
} // namespace folly
......@@ -17,6 +17,7 @@
#include <folly/FileUtil.h>
#include <folly/experimental/TestUtil.h>
#include <folly/experimental/symbolizer/Elf.h>
#include <folly/experimental/symbolizer/detail/Debug.h>
#include <folly/portability/GTest.h>
#include <sys/auxv.h>
......@@ -39,18 +40,17 @@ TEST_F(ElfTest, IntegerValue) {
}
TEST_F(ElfTest, PointerValue) {
auto rawBaseAddress = elfFile_.getBaseAddress();
auto sym = elfFile_.getSymbolByName("kStringValue");
EXPECT_NE(nullptr, sym.first) << "Failed to look up symbol kStringValue";
ElfW(Addr) addr = elfFile_.getSymbolValue<ElfW(Addr)>(sym.second);
// Let's check the address for the symbol against our own copy of
// kStringValue.
auto binaryBase = getauxval(AT_PHDR) - 0x40; // address of our own image
// For PIE binaries we need to adjust the address due to relocation.
auto binaryOffset = folly::symbolizer::detail::get_r_debug()->r_map->l_addr;
EXPECT_EQ(
static_cast<const void*>(&kStringValue),
reinterpret_cast<const void*>(
binaryBase + (sym.second->st_value - rawBaseAddress)));
if (rawBaseAddress != 0) { // non-PIE
reinterpret_cast<const void*>(binaryOffset + sym.second->st_value));
if (binaryOffset == 0) { // non-PIE
// Only do this check if we have a non-PIE. For the PIE case, the compiler
// could put a 0 in the .data section for kStringValue, and then rely on
// the dynamic linker to fill in the actual pointer to the .rodata section
......
......@@ -24,6 +24,7 @@
#include <folly/String.h>
#include <folly/experimental/symbolizer/ElfCache.h>
#include <folly/experimental/symbolizer/SymbolizedFrame.h>
#include <folly/experimental/symbolizer/detail/Debug.h>
#include <folly/experimental/symbolizer/test/SymbolizerTestUtils.h>
#include <folly/portability/GTest.h>
#include <folly/test/TestUtils.h>
......@@ -32,6 +33,12 @@ namespace folly {
namespace symbolizer {
namespace test {
namespace {
uintptr_t getBinaryOffset() {
return detail::get_r_debug()->r_map->l_addr;
}
} // namespace
void foo() {}
TEST(Symbolizer, Single) {
......@@ -160,7 +167,7 @@ void verifyStackTrace(
FrameArray<10> singleAddressFrames;
singleAddressFrames.frameCount = 1;
singleAddressFrames.addresses[0] = frames.frames[7].addr;
singleAddressFrames.addresses[0] = frames.frames[7].addr + getBinaryOffset();
// Two inline function calls are added into frames.
EXPECT_EQ(3, symbolizer.symbolize(singleAddressFrames));
}
......@@ -248,7 +255,7 @@ TEST(SymbolizerTest, InlineFunctionWithoutEnoughFrames) {
symbolizer.symbolize(frames);
// The address of the line where lexicalBlockBar calls inlineBar.
uintptr_t address = frames.frames[7].addr;
uintptr_t address = frames.frames[7].addr + getBinaryOffset();
std::array<SymbolizedFrame, 2> limitedFrames;
symbolizer.symbolize(
folly::Range<const uintptr_t*>(&address, 1), folly::range(limitedFrames));
......@@ -450,7 +457,7 @@ TEST(Dwarf, FindParameterNames) {
LocationInfo info;
folly::Range<SymbolizedFrame*> extraInlineFrames = {};
dwarf.findAddress(
address,
frame.addr,
LocationInfoMode::FAST,
info,
extraInlineFrames,
......
......@@ -27,12 +27,12 @@
#include <folly/Random.h>
#include <folly/String.h>
#include <folly/Subprocess.h>
#include <folly/experimental/symbolizer/detail/Debug.h>
#include <folly/lang/Bits.h>
#include <folly/portability/GTest.h>
#include <folly/portability/Unistd.h>
#include <folly/tracing/StaticTracepoint.h>
#include <folly/tracing/test/StaticTracepointTestModule.h>
#include <sys/auxv.h>
static const std::string kUSDTSubsectionName = FOLLY_SDT_NOTE_NAME;
static const int kUSDTNoteType = FOLLY_SDT_NOTE_TYPE;
......@@ -236,8 +236,9 @@ static bool getTracepointArguments(
}
// If the test is built as PIE, then the semaphore address listed in the
// notes section is relative to the beginning of the binary image.
auto binaryBase = getauxval(AT_PHDR) - 0x40;
CHECK_EQ(expectedSemaphore, binaryBase + semaphoreAddr);
auto binaryOffset =
folly::symbolizer::detail::get_r_debug()->r_map->l_addr;
CHECK_EQ(expectedSemaphore, binaryOffset + semaphoreAddr);
return true;
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment