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 @@ ...@@ -30,6 +30,7 @@
#include <folly/experimental/symbolizer/Elf.h> #include <folly/experimental/symbolizer/Elf.h>
#include <folly/experimental/symbolizer/ElfCache.h> #include <folly/experimental/symbolizer/ElfCache.h>
#include <folly/experimental/symbolizer/LineReader.h> #include <folly/experimental/symbolizer/LineReader.h>
#include <folly/experimental/symbolizer/detail/Debug.h>
#include <folly/lang/SafeAssert.h> #include <folly/lang/SafeAssert.h>
#include <folly/portability/Config.h> #include <folly/portability/Config.h>
#include <folly/portability/SysMman.h> #include <folly/portability/SysMman.h>
...@@ -49,25 +50,6 @@ ...@@ -49,25 +50,6 @@
#include <execinfo.h> #include <execinfo.h>
#endif #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 folly {
namespace symbolizer { namespace symbolizer {
...@@ -105,7 +87,7 @@ void setSymbolizedFrame( ...@@ -105,7 +87,7 @@ void setSymbolizedFrame(
} // namespace } // namespace
bool Symbolizer::isAvailable() { bool Symbolizer::isAvailable() {
return get_r_debug(); return detail::get_r_debug();
} }
Symbolizer::Symbolizer( Symbolizer::Symbolizer(
...@@ -126,7 +108,7 @@ size_t Symbolizer::symbolize( ...@@ -126,7 +108,7 @@ size_t Symbolizer::symbolize(
FOLLY_SAFE_CHECK(addrCount <= frameCount, "Not enough frames."); FOLLY_SAFE_CHECK(addrCount <= frameCount, "Not enough frames.");
size_t remaining = addrCount; size_t remaining = addrCount;
auto const dbg = get_r_debug(); auto const dbg = detail::get_r_debug();
if (dbg == nullptr) { if (dbg == nullptr) {
return 0; 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 @@ ...@@ -17,6 +17,7 @@
#include <folly/FileUtil.h> #include <folly/FileUtil.h>
#include <folly/experimental/TestUtil.h> #include <folly/experimental/TestUtil.h>
#include <folly/experimental/symbolizer/Elf.h> #include <folly/experimental/symbolizer/Elf.h>
#include <folly/experimental/symbolizer/detail/Debug.h>
#include <folly/portability/GTest.h> #include <folly/portability/GTest.h>
#include <sys/auxv.h> #include <sys/auxv.h>
...@@ -39,18 +40,17 @@ TEST_F(ElfTest, IntegerValue) { ...@@ -39,18 +40,17 @@ TEST_F(ElfTest, IntegerValue) {
} }
TEST_F(ElfTest, PointerValue) { TEST_F(ElfTest, PointerValue) {
auto rawBaseAddress = elfFile_.getBaseAddress();
auto sym = elfFile_.getSymbolByName("kStringValue"); auto sym = elfFile_.getSymbolByName("kStringValue");
EXPECT_NE(nullptr, sym.first) << "Failed to look up symbol kStringValue"; EXPECT_NE(nullptr, sym.first) << "Failed to look up symbol kStringValue";
ElfW(Addr) addr = elfFile_.getSymbolValue<ElfW(Addr)>(sym.second); ElfW(Addr) addr = elfFile_.getSymbolValue<ElfW(Addr)>(sym.second);
// Let's check the address for the symbol against our own copy of // Let's check the address for the symbol against our own copy of
// kStringValue. // 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( EXPECT_EQ(
static_cast<const void*>(&kStringValue), static_cast<const void*>(&kStringValue),
reinterpret_cast<const void*>( reinterpret_cast<const void*>(binaryOffset + sym.second->st_value));
binaryBase + (sym.second->st_value - rawBaseAddress))); if (binaryOffset == 0) { // non-PIE
if (rawBaseAddress != 0) { // non-PIE
// Only do this check if we have a non-PIE. For the PIE case, the compiler // 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 // 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 // the dynamic linker to fill in the actual pointer to the .rodata section
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <folly/String.h> #include <folly/String.h>
#include <folly/experimental/symbolizer/ElfCache.h> #include <folly/experimental/symbolizer/ElfCache.h>
#include <folly/experimental/symbolizer/SymbolizedFrame.h> #include <folly/experimental/symbolizer/SymbolizedFrame.h>
#include <folly/experimental/symbolizer/detail/Debug.h>
#include <folly/experimental/symbolizer/test/SymbolizerTestUtils.h> #include <folly/experimental/symbolizer/test/SymbolizerTestUtils.h>
#include <folly/portability/GTest.h> #include <folly/portability/GTest.h>
#include <folly/test/TestUtils.h> #include <folly/test/TestUtils.h>
...@@ -32,6 +33,12 @@ namespace folly { ...@@ -32,6 +33,12 @@ namespace folly {
namespace symbolizer { namespace symbolizer {
namespace test { namespace test {
namespace {
uintptr_t getBinaryOffset() {
return detail::get_r_debug()->r_map->l_addr;
}
} // namespace
void foo() {} void foo() {}
TEST(Symbolizer, Single) { TEST(Symbolizer, Single) {
...@@ -160,7 +167,7 @@ void verifyStackTrace( ...@@ -160,7 +167,7 @@ void verifyStackTrace(
FrameArray<10> singleAddressFrames; FrameArray<10> singleAddressFrames;
singleAddressFrames.frameCount = 1; 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. // Two inline function calls are added into frames.
EXPECT_EQ(3, symbolizer.symbolize(singleAddressFrames)); EXPECT_EQ(3, symbolizer.symbolize(singleAddressFrames));
} }
...@@ -248,7 +255,7 @@ TEST(SymbolizerTest, InlineFunctionWithoutEnoughFrames) { ...@@ -248,7 +255,7 @@ TEST(SymbolizerTest, InlineFunctionWithoutEnoughFrames) {
symbolizer.symbolize(frames); symbolizer.symbolize(frames);
// The address of the line where lexicalBlockBar calls inlineBar. // 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; std::array<SymbolizedFrame, 2> limitedFrames;
symbolizer.symbolize( symbolizer.symbolize(
folly::Range<const uintptr_t*>(&address, 1), folly::range(limitedFrames)); folly::Range<const uintptr_t*>(&address, 1), folly::range(limitedFrames));
...@@ -450,7 +457,7 @@ TEST(Dwarf, FindParameterNames) { ...@@ -450,7 +457,7 @@ TEST(Dwarf, FindParameterNames) {
LocationInfo info; LocationInfo info;
folly::Range<SymbolizedFrame*> extraInlineFrames = {}; folly::Range<SymbolizedFrame*> extraInlineFrames = {};
dwarf.findAddress( dwarf.findAddress(
address, frame.addr,
LocationInfoMode::FAST, LocationInfoMode::FAST,
info, info,
extraInlineFrames, extraInlineFrames,
......
...@@ -27,12 +27,12 @@ ...@@ -27,12 +27,12 @@
#include <folly/Random.h> #include <folly/Random.h>
#include <folly/String.h> #include <folly/String.h>
#include <folly/Subprocess.h> #include <folly/Subprocess.h>
#include <folly/experimental/symbolizer/detail/Debug.h>
#include <folly/lang/Bits.h> #include <folly/lang/Bits.h>
#include <folly/portability/GTest.h> #include <folly/portability/GTest.h>
#include <folly/portability/Unistd.h> #include <folly/portability/Unistd.h>
#include <folly/tracing/StaticTracepoint.h> #include <folly/tracing/StaticTracepoint.h>
#include <folly/tracing/test/StaticTracepointTestModule.h> #include <folly/tracing/test/StaticTracepointTestModule.h>
#include <sys/auxv.h>
static const std::string kUSDTSubsectionName = FOLLY_SDT_NOTE_NAME; static const std::string kUSDTSubsectionName = FOLLY_SDT_NOTE_NAME;
static const int kUSDTNoteType = FOLLY_SDT_NOTE_TYPE; static const int kUSDTNoteType = FOLLY_SDT_NOTE_TYPE;
...@@ -236,8 +236,9 @@ static bool getTracepointArguments( ...@@ -236,8 +236,9 @@ static bool getTracepointArguments(
} }
// If the test is built as PIE, then the semaphore address listed in the // 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. // notes section is relative to the beginning of the binary image.
auto binaryBase = getauxval(AT_PHDR) - 0x40; auto binaryOffset =
CHECK_EQ(expectedSemaphore, binaryBase + semaphoreAddr); folly::symbolizer::detail::get_r_debug()->r_map->l_addr;
CHECK_EQ(expectedSemaphore, binaryOffset + semaphoreAddr);
return true; 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