Skip to content

Commit 5614bc4

Browse files
authored
Merge pull request #11752 from swiftlang/dliew/demangle-trap-reason-refactor-cherry-pick-stable-21.x
🍒 [Clang][LLDB] Refactor trap reason demangling out of LLDB and into Clang (llvm#165996)
2 parents 5793c44 + 6dadfc8 commit 5614bc4

File tree

6 files changed

+122
-25
lines changed

6 files changed

+122
-25
lines changed

clang/include/clang/CodeGen/ModuleBuilder.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,23 @@ CodeGenerator *CreateLLVMCodeGen(DiagnosticsEngine &Diags,
114114
llvm::LLVMContext &C,
115115
CoverageSourceInfo *CoverageInfo = nullptr);
116116

117+
namespace CodeGen {
118+
/// Demangle the artificial function name (\param FuncName) used to encode trap
119+
/// reasons used in debug info for traps (e.g. __builtin_verbose_trap). See
120+
/// `CGDebugInfo::CreateTrapFailureMessageFor`.
121+
///
122+
/// \param FuncName - The function name to demangle.
123+
///
124+
/// \return A std::optional. If demangling succeeds the optional will contain
125+
/// a pair of StringRefs where the first field is the trap category and the
126+
/// second is the trap message. These can both be empty. If demangling fails the
127+
/// optional will not contain a value. Note the returned StringRefs if non-empty
128+
/// point into the underlying storage for \param FuncName and thus have the same
129+
/// lifetime.
130+
std::optional<std::pair<StringRef, StringRef>>
131+
DemangleTrapReasonInDebugInfo(StringRef FuncName);
132+
} // namespace CodeGen
133+
117134
} // end namespace clang
118135

119136
#endif

clang/lib/CodeGen/ModuleBuilder.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "llvm/IR/DataLayout.h"
2424
#include "llvm/IR/LLVMContext.h"
2525
#include "llvm/IR/Module.h"
26+
#include "llvm/Support/FormatVariadic.h"
2627
#include "llvm/Support/VirtualFileSystem.h"
2728
#include <memory>
2829

@@ -376,3 +377,31 @@ clang::CreateLLVMCodeGen(DiagnosticsEngine &Diags, llvm::StringRef ModuleName,
376377
HeaderSearchOpts, PreprocessorOpts, CGO, C,
377378
CoverageInfo);
378379
}
380+
381+
namespace clang {
382+
namespace CodeGen {
383+
std::optional<std::pair<StringRef, StringRef>>
384+
DemangleTrapReasonInDebugInfo(StringRef FuncName) {
385+
static auto TrapRegex =
386+
llvm::Regex(llvm::formatv("^{0}\\$(.*)\\$(.*)$", ClangTrapPrefix).str());
387+
llvm::SmallVector<llvm::StringRef, 3> Matches;
388+
std::string *ErrorPtr = nullptr;
389+
#ifndef NDEBUG
390+
std::string Error;
391+
ErrorPtr = &Error;
392+
#endif
393+
if (!TrapRegex.match(FuncName, &Matches, ErrorPtr)) {
394+
assert(ErrorPtr && ErrorPtr->empty() && "Invalid regex pattern");
395+
return {};
396+
}
397+
398+
if (Matches.size() != 3) {
399+
assert(0 && "Expected 3 matches from Regex::match");
400+
return {};
401+
}
402+
403+
// Returns { Trap Category, Trap Message }
404+
return std::make_pair(Matches[1], Matches[2]);
405+
}
406+
} // namespace CodeGen
407+
} // namespace clang

clang/unittests/CodeGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
add_clang_unittest(ClangCodeGenTests
22
BufferSourceTest.cpp
33
CodeGenExternalTest.cpp
4+
DemangleTrapReasonInDebugInfo.cpp
45
TBAAMetadataTest.cpp
56
CheckTargetFeaturesTest.cpp
67
CLANG_LIBS
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//=== unittests/CodeGen/DemangleTrapReasonInDebugInfo.cpp -----------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "clang/CodeGen/ModuleBuilder.h"
10+
#include "llvm/ADT/StringRef.h"
11+
#include "gtest/gtest.h"
12+
13+
using namespace clang::CodeGen;
14+
15+
void CheckValidCommon(llvm::StringRef FuncName, const char *ExpectedCategory,
16+
const char *ExpectedMessage) {
17+
auto MaybeTrapReason = DemangleTrapReasonInDebugInfo(FuncName);
18+
ASSERT_TRUE(MaybeTrapReason.has_value());
19+
auto [Category, Message] = MaybeTrapReason.value();
20+
ASSERT_STREQ(Category.str().c_str(), ExpectedCategory);
21+
ASSERT_STREQ(Message.str().c_str(), ExpectedMessage);
22+
}
23+
24+
void CheckInvalidCommon(llvm::StringRef FuncName) {
25+
auto MaybeTrapReason = DemangleTrapReasonInDebugInfo(FuncName);
26+
ASSERT_TRUE(!MaybeTrapReason.has_value());
27+
}
28+
29+
TEST(DemangleTrapReasonInDebugInfo, Valid) {
30+
std::string FuncName(ClangTrapPrefix);
31+
FuncName += "$trap category$trap message";
32+
CheckValidCommon(FuncName, "trap category", "trap message");
33+
}
34+
35+
TEST(DemangleTrapReasonInDebugInfo, ValidEmptyCategory) {
36+
std::string FuncName(ClangTrapPrefix);
37+
FuncName += "$$trap message";
38+
CheckValidCommon(FuncName, "", "trap message");
39+
}
40+
41+
TEST(DemangleTrapReasonInDebugInfo, ValidEmptyMessage) {
42+
std::string FuncName(ClangTrapPrefix);
43+
FuncName += "$trap category$";
44+
CheckValidCommon(FuncName, "trap category", "");
45+
}
46+
47+
TEST(DemangleTrapReasonInDebugInfo, ValidAllEmpty) {
48+
// `__builtin_verbose_trap` actually allows this
49+
// currently. However, we should probably disallow this in Sema because having
50+
// an empty category and message completely defeats the point of using the
51+
// builtin (#165981).
52+
std::string FuncName(ClangTrapPrefix);
53+
FuncName += "$$";
54+
CheckValidCommon(FuncName, "", "");
55+
}
56+
57+
TEST(DemangleTrapReasonInDebugInfo, InvalidOnlyPrefix) {
58+
std::string FuncName(ClangTrapPrefix);
59+
CheckInvalidCommon(FuncName);
60+
}
61+
62+
TEST(DemangleTrapReasonInDebugInfo, Invalid) {
63+
std::string FuncName("foo");
64+
CheckInvalidCommon(FuncName);
65+
}
66+
67+
TEST(DemangleTrapReasonInDebugInfo, InvalidEmpty) { CheckInvalidCommon(""); }

lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ add_lldb_library(lldbPluginCPPRuntime
66
lldbCore
77
lldbSymbol
88
lldbTarget
9+
CLANG_LIBS
10+
clangCodeGen
911
)
1012

1113
add_subdirectory(ItaniumABI)

lldb/source/Plugins/LanguageRuntime/CPlusPlus/VerboseTrapFrameRecognizer.cpp

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -101,33 +101,14 @@ VerboseTrapFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) {
101101
if (func_name.empty())
102102
return {};
103103

104-
static auto trap_regex =
105-
llvm::Regex(llvm::formatv("^{0}\\$(.*)\\$(.*)$", ClangTrapPrefix).str());
106-
SmallVector<llvm::StringRef, 3> matches;
107-
std::string regex_err_msg;
108-
if (!trap_regex.match(func_name, &matches, &regex_err_msg)) {
109-
LLDB_LOGF(GetLog(LLDBLog::Unwind),
110-
"Failed to parse match trap regex for '%s': %s", func_name.data(),
111-
regex_err_msg.c_str());
112-
113-
return {};
114-
}
115-
116-
// For `__clang_trap_msg$category$message$` we expect 3 matches:
117-
// 1. entire string
118-
// 2. category
119-
// 3. message
120-
if (matches.size() != 3) {
121-
LLDB_LOGF(GetLog(LLDBLog::Unwind),
122-
"Unexpected function name format. Expected '<trap prefix>$<trap "
123-
"category>$<trap message>'$ but got: '%s'.",
124-
func_name.data());
125-
104+
auto maybe_trap_reason =
105+
clang::CodeGen::DemangleTrapReasonInDebugInfo(func_name);
106+
if (!maybe_trap_reason.has_value()) {
107+
LLDB_LOGF(GetLog(LLDBLog::Unwind), "Failed to demangle '%s' as trap reason",
108+
func_name.str().c_str());
126109
return {};
127110
}
128-
129-
auto category = matches[1];
130-
auto message = matches[2];
111+
auto [category, message] = maybe_trap_reason.value();
131112

132113
std::string stop_reason =
133114
category.empty() ? "<empty category>" : category.str();

0 commit comments

Comments
 (0)