Commit 2d2c15fc authored by Matt Ma's avatar Matt Ma Committed by Facebook GitHub Bot

Fix and refactor inline functions stack trace.

Summary:
Fix the issue that there may be other tags like DW_TAG_lexical_block between DW_TAG_subprogram and DW_TAG_inlined_subroutine.

Also increase the maximum inline location info per frame since previous value 3 is too small.

Refactors the code to set file and line for inline functions.

Reviewed By: luciang

Differential Revision: D21250080

fbshipit-source-id: f52dc74ee5c144aa26723546b48486f8a5250f19
parent 8228e607
This diff is collapsed.
......@@ -44,7 +44,7 @@ struct DIEAbbreviation;
struct AttributeSpec;
struct Attribute;
struct CodeLocation;
struct CallLocation;
} // namespace detail
......@@ -85,7 +85,7 @@ class Dwarf {
* More than one location info may exist if current frame is an inline
* function call.
*/
static const uint32_t kMaxInlineLocationInfoPerFrame = 3;
static const uint32_t kMaxInlineLocationInfoPerFrame = 10;
/** Find the file and line number information corresponding to address. */
bool findAddress(
......@@ -136,8 +136,10 @@ class Dwarf {
void findInlinedSubroutineDieForAddress(
const detail::CompilationUnit& cu,
const detail::Die& die,
const LineNumberVM& lineVM,
uint64_t address,
folly::Range<detail::CodeLocation*>& isrLoc) const;
folly::Range<detail::CallLocation*> locations,
size_t& numFound) const;
static bool
findDebugInfoOffset(uintptr_t address, StringPiece aranges, uint64_t& offset);
......
......@@ -18,27 +18,40 @@
#include <folly/Range.h>
#include <folly/experimental/symbolizer/Dwarf.h>
#include <folly/experimental/symbolizer/SymbolizedFrame.h>
#include <folly/experimental/symbolizer/test/SymbolizerTestUtils.h>
#include <folly/portability/GFlags.h>
void dummy() {}
namespace {
using namespace folly::symbolizer;
using namespace folly::symbolizer::test;
template <size_t kNumFrames>
FOLLY_NOINLINE void lexicalBlockBar(FrameArray<kNumFrames>& frames) try {
size_t unused = 0;
unused++;
inlineBar(frames);
} catch (...) {
folly::assume_unreachable();
}
void run(LocationInfoMode mode, size_t n) {
folly::BenchmarkSuspender suspender;
// NOTE: Using '/proc/self/exe' only works if the code for @dummy is
// statically linked into the binary.
Symbolizer symbolizer(nullptr, LocationInfoMode::FULL_WITH_INLINE, 0);
FrameArray<100> frames;
lexicalBlockBar<100>(frames);
symbolizer.symbolize(frames);
// The address of the line where lexicalBlockBar calls inlineBar.
uintptr_t address = frames.frames[7].addr;
ElfFile elf("/proc/self/exe");
Dwarf dwarf(&elf);
auto inlineFrames = std::array<SymbolizedFrame, 10>();
suspender.dismiss();
for (size_t i = 0; i < n; i++) {
LocationInfo info;
auto inlineFrames =
std::array<SymbolizedFrame, Dwarf::kMaxInlineLocationInfoPerFrame>();
dwarf.findAddress(
uintptr_t(&dummy), mode, info, folly::range(inlineFrames));
dwarf.findAddress(address, mode, info, folly::range(inlineFrames));
}
}
......
......@@ -123,10 +123,14 @@ TEST(SymbolizerTest, SymbolCache) {
namespace {
template <size_t kNumFrames = 100>
FOLLY_ALWAYS_INLINE void inlineBar(FrameArray<kNumFrames>& frames) {
kFooCallByStandaloneBarLineNo = __LINE__ + 1;
inlineFoo(frames);
template <size_t kNumFrames>
FOLLY_NOINLINE void lexicalBlockBar(FrameArray<kNumFrames>& frames) try {
size_t unused = 0;
unused++;
kInlineBarCallByLexicalBarLineNo = __LINE__ + 1;
inlineBar(frames);
} catch (...) {
folly::assume_unreachable();
}
void verifyStackTrace(
......@@ -139,7 +143,7 @@ void verifyStackTrace(
"folly::symbolizer::FrameArray<100ul>&)",
std::string(folly::demangle(frames.frames[5].name)));
EXPECT_EQ(
"folly/experimental/symbolizer/test/SymbolizerTestUtils-inl.h",
"./folly/experimental/symbolizer/test/SymbolizerTestUtils-inl.h",
std::string(frames.frames[5].location.file.toString()));
EXPECT_EQ(kQsortCallLineNo, frames.frames[5].location.line);
EXPECT_EQ(barName, std::string(folly::demangle(frames.frames[6].name)));
......@@ -205,10 +209,10 @@ TEST(SymbolizerTest, InlineFunctionBasic) {
// clang-format on
verifyStackTrace(
frames,
"void folly::symbolizer::test::(anonymous namespace)::inlineBar<100ul>("
"void folly::symbolizer::test::inlineBar<100ul>("
"folly::symbolizer::FrameArray<100ul>&)",
kFooCallByStandaloneBarLineNo,
"folly/experimental/symbolizer/test/SymbolizerTest.cpp");
"folly/experimental/symbolizer/test/SymbolizerTestUtils-inl.h");
FrameArray<100> frames2;
inlineBar<100>(frames2);
......@@ -217,6 +221,80 @@ TEST(SymbolizerTest, InlineFunctionBasic) {
compareFrames(frames, frames2);
}
TEST(SymbolizerTest, InlineFunctionWithoutEnoughFrames) {
Symbolizer symbolizer(nullptr, LocationInfoMode::FULL_WITH_INLINE, 0);
FrameArray<100> frames;
lexicalBlockBar<100>(frames);
symbolizer.symbolize(frames);
// The address of the line where lexicalBlockBar calls inlineBar.
uintptr_t address = frames.frames[7].addr;
std::array<SymbolizedFrame, 2> limitedFrames;
symbolizer.symbolize(
folly::Range<const uintptr_t*>(&address, 1), folly::range(limitedFrames));
EXPECT_EQ(
"void folly::symbolizer::test::inlineBar<100ul>("
"folly::symbolizer::FrameArray<100ul>&)",
std::string(folly::demangle(limitedFrames[0].name)));
EXPECT_EQ(
"folly/experimental/symbolizer/test/SymbolizerTestUtils-inl.h",
std::string(limitedFrames[0].location.file.toString()));
EXPECT_EQ(kFooCallByStandaloneBarLineNo, limitedFrames[0].location.line);
EXPECT_EQ(
"void folly::symbolizer::test::(anonymous namespace)::lexicalBlockBar"
"<100ul>(folly::symbolizer::FrameArray<100ul>&)",
std::string(folly::demangle(limitedFrames[1].name)));
EXPECT_EQ(
"folly/experimental/symbolizer/test/SymbolizerTest.cpp",
std::string(limitedFrames[1].location.file.toString()));
EXPECT_EQ(kInlineBarCallByLexicalBarLineNo, limitedFrames[1].location.line);
}
TEST(SymbolizerTest, InlineFunctionInLexicalBlock) {
Symbolizer symbolizer(nullptr, LocationInfoMode::FULL_WITH_INLINE, 0);
FrameArray<100> frames;
lexicalBlockBar<100>(frames);
symbolizer.symbolize(frames);
verifyStackTrace(
frames,
"void folly::symbolizer::test::inlineBar<100ul>("
"folly::symbolizer::FrameArray<100ul>&)",
kFooCallByStandaloneBarLineNo,
"folly/experimental/symbolizer/test/SymbolizerTestUtils-inl.h");
EXPECT_EQ(
"void folly::symbolizer::test::(anonymous namespace)::lexicalBlockBar"
"<100ul>(folly::symbolizer::FrameArray<100ul>&)",
std::string(folly::demangle(frames.frames[7].name)));
EXPECT_EQ(
"folly/experimental/symbolizer/test/SymbolizerTest.cpp",
std::string(frames.frames[7].location.file.toString()));
EXPECT_EQ(kInlineBarCallByLexicalBarLineNo, frames.frames[7].location.line);
}
TEST(SymbolizerTest, InlineFunctionInDifferentCompilationUnit) {
Symbolizer symbolizer(nullptr, LocationInfoMode::FULL_WITH_INLINE, 0);
FrameArray<100> frames;
// NOTE: inlineBaz is only inlined with thinlto compilation mode enabled.
inlineBaz(frames);
symbolizer.symbolize(frames);
EXPECT_EQ(
"folly::symbolizer::test::inlineBaz("
"folly::symbolizer::FrameArray<100ul>&)",
std::string(folly::demangle(frames.frames[6].name)));
EXPECT_EQ(
"folly/experimental/symbolizer/test/SymbolizerTestUtils.cpp",
std::string(frames.frames[6].location.file.toString()));
EXPECT_EQ(kFooCallByStandaloneBazLineNo, frames.frames[6].location.line);
}
TEST(SymbolizerTest, InlineClassMemberFunction) {
Symbolizer symbolizer(nullptr, LocationInfoMode::FULL_WITH_INLINE, 0);
......@@ -303,10 +381,10 @@ TEST(SymbolizerTest, InlineFunctionWithCache) {
verifyStackTrace(
frames,
"void folly::symbolizer::test::(anonymous namespace)::inlineBar<100ul>("
"void folly::symbolizer::test::inlineBar<100ul>("
"folly::symbolizer::FrameArray<100ul>&)",
kFooCallByStandaloneBarLineNo,
"folly/experimental/symbolizer/test/SymbolizerTest.cpp");
"folly/experimental/symbolizer/test/SymbolizerTestUtils-inl.h");
FrameArray<100> frames2;
inlineBar<100>(frames2);
......
......@@ -35,6 +35,12 @@ FOLLY_ALWAYS_INLINE void inlineFoo(FrameArray<kNumFrames>& frames) {
framesToFill = nullptr;
}
template <size_t kNumFrames>
FOLLY_ALWAYS_INLINE void inlineBar(FrameArray<kNumFrames>& frames) {
kFooCallByStandaloneBarLineNo = __LINE__ + 1;
inlineFoo(frames);
}
FOLLY_ALWAYS_INLINE void InlineFunctionsWrapper::inlineBar(
FrameArray<100>& frames) const {
kFooCallByClassInDifferentFileBarLineNo = __LINE__ + 1;
......
/*
* 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.
*/
#include <folly/experimental/symbolizer/test/SymbolizerTestUtils.h>
namespace folly {
namespace symbolizer {
namespace test {
void* framesToFill = {nullptr};
size_t kQsortCallLineNo = 0;
size_t kFooCallByStandaloneBarLineNo = 0;
size_t kFooCallByStandaloneBazLineNo = 0;
size_t kFooCallByClassBarLineNo = 0;
size_t kFooCallByClassStaticBarLineNo = 0;
size_t kFooCallByClassInDifferentFileBarLineNo = 0;
size_t kFooCallByClassInDifferentFileStaticBarLineNo = 0;
size_t kInlineBarCallByLexicalBarLineNo = 0;
size_t kInlineBazCallByLexicalBazLineNo = 0;
void inlineBaz(FrameArray<100>& frames) {
kFooCallByStandaloneBazLineNo = __LINE__ + 1;
inlineFoo(frames);
}
} // namespace test
} // namespace symbolizer
} // namespace folly
......@@ -23,7 +23,7 @@ namespace folly {
namespace symbolizer {
namespace test {
void* framesToFill{nullptr};
extern void* framesToFill;
template <size_t kNumFrames = 100>
int comparator(const void* ap, const void* bp) {
......@@ -34,16 +34,23 @@ int comparator(const void* ap, const void* bp) {
return a < b ? -1 : a > b ? 1 : 0;
}
size_t kQsortCallLineNo = 0;
size_t kFooCallByStandaloneBarLineNo = 0;
size_t kFooCallByClassBarLineNo = 0;
size_t kFooCallByClassStaticBarLineNo = 0;
size_t kFooCallByClassInDifferentFileBarLineNo = 0;
size_t kFooCallByClassInDifferentFileStaticBarLineNo = 0;
extern size_t kQsortCallLineNo;
extern size_t kFooCallByStandaloneBarLineNo;
extern size_t kFooCallByStandaloneBazLineNo;
extern size_t kFooCallByClassBarLineNo;
extern size_t kFooCallByClassStaticBarLineNo;
extern size_t kFooCallByClassInDifferentFileBarLineNo;
extern size_t kFooCallByClassInDifferentFileStaticBarLineNo;
extern size_t kInlineBarCallByLexicalBarLineNo;
template <size_t kNumFrames = 100>
FOLLY_ALWAYS_INLINE void inlineFoo(FrameArray<kNumFrames>& frames);
template <size_t kNumFrames = 100>
FOLLY_ALWAYS_INLINE void inlineBar(FrameArray<kNumFrames>& frames);
extern void inlineBaz(FrameArray<100>& frames);
class InlineFunctionsWrapper {
public:
FOLLY_ALWAYS_INLINE void inlineBar(FrameArray<100>& frames) const;
......
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