proxygen
SymbolizerTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2013-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
18 
19 #include <cstdlib>
20 
21 #include <folly/Range.h>
22 #include <folly/String.h>
24 
25 namespace folly {
26 namespace symbolizer {
27 namespace test {
28 
29 void foo() {}
30 
31 TEST(Symbolizer, Single) {
32  Symbolizer symbolizer;
34  ASSERT_TRUE(symbolizer.symbolize(reinterpret_cast<uintptr_t>(foo), a));
35  EXPECT_EQ("folly::symbolizer::test::foo()", a.demangledName());
36 
37  // The version of clang we use doesn't generate a `.debug_aranges` section,
38  // which the symbolizer needs to lookup the filename.
39  constexpr bool built_with_clang =
40 #ifdef __clang__
41  true;
42 #else
43  false;
44 #endif
45  if (!built_with_clang) {
46  auto path = a.location.file.toString();
47  folly::StringPiece basename(path);
48  auto pos = basename.rfind('/');
49  if (pos != folly::StringPiece::npos) {
50  basename.advance(pos + 1);
51  }
52  EXPECT_EQ("SymbolizerTest.cpp", basename.str());
53  }
54 }
55 
57 
58 int comparator(const void* ap, const void* bp) {
60 
61  int a = *static_cast<const int*>(ap);
62  int b = *static_cast<const int*>(bp);
63  return a < b ? -1 : a > b ? 1 : 0;
64 }
65 
66 // Test stack frames...
67 FOLLY_NOINLINE void bar();
68 
69 void bar(FrameArray<100>& frames) {
70  framesToFill = &frames;
71  int a[2] = {1, 2};
72  // Use qsort, which is in a different library
73  qsort(a, 2, sizeof(int), comparator);
74  framesToFill = nullptr;
75 }
76 
77 class ElfCacheTest : public testing::Test {
78  protected:
79  void SetUp() override;
80 };
81 
82 // Capture "golden" stack trace with default-configured Symbolizer
84 
86  bar(goldenFrames);
87  Symbolizer symbolizer;
88  symbolizer.symbolize(goldenFrames);
89  // At least 3 stack frames from us + getStackTrace()
90  ASSERT_LE(4, goldenFrames.frameCount);
91 }
92 
93 void runElfCacheTest(Symbolizer& symbolizer) {
95  for (size_t i = 0; i < frames.frameCount; ++i) {
96  frames.frames[i].clear();
97  }
98  symbolizer.symbolize(frames);
99  ASSERT_LE(4, frames.frameCount);
100  for (size_t i = 1; i < 4; ++i) {
101  EXPECT_STREQ(goldenFrames.frames[i].name, frames.frames[i].name);
102  }
103 }
104 
105 TEST_F(ElfCacheTest, TinyElfCache) {
106  ElfCache cache(1);
107  Symbolizer symbolizer(&cache);
108  // Run twice, in case the wrong stuff gets evicted?
109  for (size_t i = 0; i < 2; ++i) {
110  runElfCacheTest(symbolizer);
111  }
112 }
113 
115  SignalSafeElfCache cache(100);
116  Symbolizer symbolizer(&cache);
117  for (size_t i = 0; i < 2; ++i) {
118  runElfCacheTest(symbolizer);
119  }
120 }
121 
122 TEST(SymbolizerTest, SymbolCache) {
123  Symbolizer symbolizer(nullptr, Dwarf::LocationInfoMode::FULL, 100);
124 
125  FrameArray<100> frames;
126  bar(frames);
127  symbolizer.symbolize(frames);
128 
129  FrameArray<100> frames2;
130  bar(frames2);
131  symbolizer.symbolize(frames2);
132  for (size_t i = 0; i < frames.frameCount; i++) {
133  EXPECT_STREQ(frames.frames[i].name, frames2.frames[i].name);
134  }
135 }
136 
137 } // namespace test
138 } // namespace symbolizer
139 } // namespace folly
140 
141 // Can't use initFacebookLight since that would install its own signal handlers
142 // Can't use initFacebookNoSignals since we cannot depend on common
143 int main(int argc, char** argv) {
144  ::testing::InitGoogleTest(&argc, argv);
145  return RUN_ALL_TESTS();
146 }
int main(int argc, char **argv)
std::string str() const
Definition: Range.h:591
char b
int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_
Definition: gtest.h:2232
Dwarf::LocationInfo location
Definition: Symbolizer.h:58
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
void advance(size_type n)
Definition: Range.h:672
#define ASSERT_LE(val1, val2)
Definition: gtest.h:1964
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
TEST(LineReader, Simple)
FOLLY_NOINLINE void bar()
#define EXPECT_STREQ(s1, s2)
Definition: gtest.h:1995
void runElfCacheTest(Symbolizer &symbolizer)
#define FOLLY_NOINLINE
Definition: CPortability.h:142
char ** argv
ssize_t getStackTrace(uintptr_t *addresses, size_t maxAddresses)
Definition: StackTrace.cpp:25
size_type rfind(value_type c) const
Definition: Range.h:761
int comparator(const void *ap, const void *bp)
char a
FrameArray< 100 > goldenFrames
SymbolizedFrame frames[N]
Definition: Symbolizer.h:77
FrameArray< 100 > * framesToFill
void toString(std::string &dest) const
Definition: Dwarf.cpp:262
fbstring demangledName() const
Definition: Symbolizer.h:63
static const size_type npos
Definition: Range.h:197
GTEST_API_ void InitGoogleTest(int *argc, char **argv)
Definition: gtest.cc:5370
TEST_F(ElfCacheTest, TinyElfCache)
void symbolize(const uintptr_t *addresses, SymbolizedFrame *frames, size_t frameCount)
Definition: Symbolizer.cpp:94
#define ASSERT_TRUE(condition)
Definition: gtest.h:1865