Skip to content

Commit 2e1f044

Browse files
Chandhana Solainathanmeta-codesync[bot]
authored andcommitted
Add throw-site stack trace capture with Linux implementation
Summary: Hooks into __cxa_throw to capture stack traces at the throw site on Linux using folly::exception_tracer Reviewed By: vilatto, janezhang10 Differential Revision: D96944408 fbshipit-source-id: 5439280516bc430a329a94f65c4d55d4060a6b9c
1 parent 5e890d1 commit 2e1f044

File tree

5 files changed

+161
-0
lines changed

5 files changed

+161
-0
lines changed

eden/fs/telemetry/BUCK

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,22 @@ cpp_library(
115115
],
116116
)
117117

118+
cpp_library(
119+
name = "throw_trace_capture",
120+
srcs = [
121+
"ThrowTraceCapture.cpp",
122+
],
123+
headers = [
124+
"ThrowTraceCapture.h",
125+
],
126+
deps = [
127+
"//folly/debugging/exception_tracer:exception_tracer_base",
128+
],
129+
exported_deps = [
130+
"//folly/debugging/exception_tracer:exception_tracer", # @manual
131+
],
132+
)
133+
118134
cpp_library(
119135
name = "error_info",
120136
srcs = [
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This software may be used and distributed according to the terms of the
5+
* GNU General Public License version 2.
6+
*/
7+
8+
#include "eden/fs/telemetry/ThrowTraceCapture.h"
9+
10+
#ifdef __linux__
11+
// =============================================================================
12+
// Linux: folly::exception_tracer
13+
//
14+
// Uses __cxa_throw hook (via --wrap linker flag) to capture stack frames at
15+
// throw time. Frames are stored in thread-local StackTraceStack and symbolized
16+
// via folly's ELF/DWARF symbolizer.
17+
// =============================================================================
18+
19+
#include <sstream>
20+
21+
#include <folly/debugging/exception_tracer/ExceptionTracer.h>
22+
23+
namespace facebook::eden {
24+
25+
std::optional<std::string> getThrowSiteStackTrace() {
26+
auto exceptions = folly::exception_tracer::getCurrentExceptions();
27+
if (!exceptions.empty()) {
28+
std::ostringstream ss;
29+
for (const auto& info : exceptions) {
30+
ss << info;
31+
}
32+
auto trace = ss.str();
33+
if (!trace.empty()) {
34+
return trace;
35+
}
36+
}
37+
return std::nullopt;
38+
}
39+
40+
} // namespace facebook::eden
41+
42+
#else
43+
// =============================================================================
44+
// Unsupported platform — no throw-site stack traces available.
45+
// =============================================================================
46+
47+
namespace facebook::eden {
48+
49+
std::optional<std::string> getThrowSiteStackTrace() {
50+
return std::nullopt;
51+
}
52+
53+
} // namespace facebook::eden
54+
55+
#endif // __linux__
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This software may be used and distributed according to the terms of the
5+
* GNU General Public License version 2.
6+
*/
7+
8+
#pragma once
9+
10+
#include <optional>
11+
#include <string>
12+
13+
namespace facebook::eden {
14+
15+
/**
16+
* Returns the throw-site stack trace for the current exception.
17+
* Must be called inside a catch block.
18+
*
19+
* Platform-specific implementations:
20+
* Linux: folly::exception_tracer (hooks __cxa_throw via --wrap)
21+
* macOS: Not yet implemented (returns std::nullopt)
22+
* Windows: Not yet implemented (returns std::nullopt)
23+
*/
24+
std::optional<std::string> getThrowSiteStackTrace();
25+
26+
} // namespace facebook::eden

eden/fs/telemetry/test/BUCK

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,19 @@ cpp_benchmark(
6262
],
6363
)
6464

65+
cpp_unittest(
66+
name = "throw_trace_capture_test",
67+
srcs = [
68+
"ThrowTraceCaptureTest.cpp",
69+
],
70+
supports_static_listing = False,
71+
deps = [
72+
"fbsource//third-party/googletest:gtest",
73+
"//eden/fs/telemetry:throw_trace_capture",
74+
"//folly:c_portability",
75+
],
76+
)
77+
6578
cpp_unittest(
6679
name = "error_info_builder_test",
6780
srcs = [
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This software may be used and distributed according to the terms of the
5+
* GNU General Public License version 2.
6+
*/
7+
8+
#include "eden/fs/telemetry/ThrowTraceCapture.h"
9+
10+
#include <stdexcept>
11+
12+
#include <folly/CPortability.h>
13+
#include <gtest/gtest.h>
14+
15+
using namespace facebook::eden;
16+
17+
#ifdef __linux__
18+
namespace {
19+
20+
[[noreturn]] FOLLY_NOINLINE void innerThrowingFunc() {
21+
throw std::runtime_error("inner error");
22+
}
23+
24+
[[noreturn]] FOLLY_NOINLINE void outerThrowingFunc() {
25+
innerThrowingFunc();
26+
}
27+
28+
} // namespace
29+
#endif
30+
31+
TEST(ThrowTraceCaptureTest, CapturesThrowSiteStackTrace) {
32+
#ifndef __linux__
33+
GTEST_SKIP() << "Stack trace capture not yet implemented on this platform";
34+
#else
35+
try {
36+
outerThrowingFunc();
37+
} catch (const std::exception&) {
38+
auto trace = getThrowSiteStackTrace();
39+
ASSERT_TRUE(trace.has_value()) << "Stack trace capture is broken";
40+
EXPECT_NE(trace->find("innerThrowingFunc"), std::string::npos)
41+
<< "Expected throw-site function in trace, got: " << *trace;
42+
EXPECT_NE(trace->find("outerThrowingFunc"), std::string::npos)
43+
<< "Expected caller function in trace, got: " << *trace;
44+
}
45+
#endif
46+
}
47+
48+
TEST(ThrowTraceCaptureTest, ReturnsNulloptOutsideCatchBlock) {
49+
auto trace = getThrowSiteStackTrace();
50+
EXPECT_FALSE(trace.has_value());
51+
}

0 commit comments

Comments
 (0)