Skip to content

Commit 0f4e47e

Browse files
Merge pull request #1844 from zhaomaosu/implement-symbolizer
[DeviceSanitizer] Implement symbolizer for more readable information
2 parents 2e6c1de + dac2a0f commit 0f4e47e

File tree

6 files changed

+161
-3
lines changed

6 files changed

+161
-3
lines changed

CMakeLists.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66
cmake_minimum_required(VERSION 3.20.0 FATAL_ERROR)
77
project(unified-runtime VERSION 0.10.0)
88

9+
# Check if unified runtime is built as a standalone project.
10+
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR UR_STANDALONE_BUILD)
11+
set(UR_STANDALONE_BUILD TRUE)
12+
endif()
13+
914
include(GNUInstallDirs)
1015
include(CheckCXXSourceCompiles)
1116
include(CMakePackageConfigHelpers)
@@ -37,6 +42,7 @@ option(UR_USE_MSAN "enable MemorySanitizer" OFF)
3742
option(UR_USE_TSAN "enable ThreadSanitizer" OFF)
3843
option(UR_ENABLE_TRACING "enable api tracing through xpti" OFF)
3944
option(UR_ENABLE_SANITIZER "enable device sanitizer" ON)
45+
option(UR_ENABLE_SYMBOLIZER "enable symoblizer for sanitizer" OFF)
4046
option(UMF_BUILD_SHARED_LIBRARY "Build UMF as shared library" ON)
4147
option(UMF_ENABLE_POOL_TRACKING "Build UMF with pool tracking" ON)
4248
option(UR_BUILD_ADAPTER_L0 "Build the Level-Zero adapter" OFF)
@@ -163,6 +169,14 @@ if(UR_ENABLE_SANITIZER)
163169
else()
164170
add_compile_definitions(UR_ENABLE_SANITIZER)
165171
endif()
172+
173+
if(UR_ENABLE_SYMBOLIZER AND UR_STANDALONE_BUILD)
174+
find_package(LLVM REQUIRED)
175+
endif()
176+
else()
177+
if(UR_ENABLE_SYMBOLIZER)
178+
message(FATAL_ERROR "Symbolizer must be enabled with Sanitizer layer")
179+
endif()
166180
endif()
167181

168182
if(UR_USE_ASAN)

source/loader/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,15 @@ if(UR_ENABLE_SANITIZER)
158158
${CMAKE_CURRENT_SOURCE_DIR}/layers/sanitizer/linux/sanitizer_utils.cpp
159159
)
160160

161+
if(UR_ENABLE_SYMBOLIZER)
162+
target_sources(ur_loader
163+
PRIVATE
164+
${CMAKE_CURRENT_SOURCE_DIR}/layers/sanitizer/linux/symbolizer.cpp
165+
)
166+
target_include_directories(ur_loader PRIVATE ${LLVM_INCLUDE_DIRS})
167+
target_link_libraries(ur_loader PRIVATE LLVMSymbolize)
168+
endif()
169+
161170
target_include_directories(ur_loader PRIVATE
162171
"${CMAKE_CURRENT_SOURCE_DIR}/layers/sanitizer"
163172
"${CMAKE_CURRENT_SOURCE_DIR}/../"

source/loader/layers/sanitizer/common.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ using BacktraceInfo = std::string;
132132
struct SourceInfo {
133133
std::string file;
134134
std::string function;
135-
int line;
136-
int column;
135+
int line = 0;
136+
int column = 0;
137137
};
138138

139139
enum class DeviceType : uint64_t { UNKNOWN = 0, CPU, GPU_PVC, GPU_DG2 };

source/loader/layers/sanitizer/linux/backtrace.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ StackTrace GetCurrentBacktrace() {
2626
StackTrace Stack;
2727
for (int i = 0; i < FrameCount; i++) {
2828
BacktraceInfo addr_info(Symbols[i]);
29-
Stack.stack.emplace_back(std::move(addr_info));
29+
Stack.stack.emplace_back(addr_info);
3030
}
3131
free(Symbols);
3232

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
*
3+
* Copyright (C) 2024 Intel Corporation
4+
*
5+
* Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM Exceptions.
6+
* See LICENSE.TXT
7+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8+
*
9+
*/
10+
#include "llvm/DebugInfo/Symbolize/DIPrinter.h"
11+
#include "llvm/DebugInfo/Symbolize/Symbolize.h"
12+
13+
namespace ur_sanitizer_layer {
14+
15+
llvm::symbolize::LLVMSymbolizer *GetSymbolizer() {
16+
static llvm::symbolize::LLVMSymbolizer Symbolizer;
17+
return &Symbolizer;
18+
}
19+
20+
llvm::symbolize::PrinterConfig GetPrinterConfig() {
21+
llvm::symbolize::PrinterConfig Config;
22+
Config.Pretty = false;
23+
Config.PrintAddress = false;
24+
Config.PrintFunctions = true;
25+
Config.SourceContextLines = 0;
26+
Config.Verbose = false;
27+
return Config;
28+
}
29+
30+
} // namespace ur_sanitizer_layer
31+
32+
extern "C" {
33+
34+
bool SymbolizeCode(const std::string ModuleName, uint64_t ModuleOffset,
35+
std::string &Result) {
36+
llvm::raw_string_ostream OS(Result);
37+
llvm::symbolize::Request Request{ModuleName, ModuleOffset};
38+
llvm::symbolize::PrinterConfig Config =
39+
ur_sanitizer_layer::GetPrinterConfig();
40+
llvm::symbolize::ErrorHandler EH = [&](const llvm::ErrorInfoBase &ErrorInfo,
41+
llvm::StringRef ErrorBanner) {
42+
OS << ErrorBanner;
43+
ErrorInfo.log(OS);
44+
OS << '\n';
45+
};
46+
auto Printer =
47+
std::make_unique<llvm::symbolize::LLVMPrinter>(OS, EH, Config);
48+
49+
auto ResOrErr = ur_sanitizer_layer::GetSymbolizer()->symbolizeInlinedCode(
50+
ModuleName,
51+
{ModuleOffset, llvm::object::SectionedAddress::UndefSection});
52+
53+
if (!ResOrErr) {
54+
return false;
55+
}
56+
Printer->print(Request, *ResOrErr);
57+
ur_sanitizer_layer::GetSymbolizer()->pruneCache();
58+
return true;
59+
}
60+
}

source/loader/layers/sanitizer/stacktrace.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@
1313
#include "stacktrace.hpp"
1414
#include "ur_sanitizer_layer.hpp"
1515

16+
extern "C" {
17+
18+
__attribute__((weak)) bool SymbolizeCode(const std::string ModuleName,
19+
uint64_t ModuleOffset,
20+
std::string &Result);
21+
}
22+
1623
namespace ur_sanitizer_layer {
1724

1825
namespace {
@@ -21,6 +28,54 @@ bool Contains(const std::string &s, const char *p) {
2128
return s.find(p) != std::string::npos;
2229
}
2330

31+
// Parse back trace information in the following formats:
32+
// <module_name>([function_name]+function_offset) [offset]
33+
void ParseBacktraceInfo(BacktraceInfo BI, std::string &ModuleName,
34+
uptr &Offset) {
35+
// Parse module name
36+
size_t End = BI.find_first_of('(');
37+
assert(End != std::string::npos);
38+
ModuleName = BI.substr(0, End);
39+
// Parse offset
40+
size_t Start = BI.find_first_of('[');
41+
assert(Start != std::string::npos);
42+
Start = BI.substr(Start + 1, 2) == "0x" ? Start + 3 : Start + 1;
43+
End = BI.find_first_of(']');
44+
assert(End != std::string::npos);
45+
Offset = std::stoull(BI.substr(Start, End), nullptr, 16);
46+
return;
47+
}
48+
49+
// Parse symbolizer output in the following formats:
50+
// <function_name>
51+
// <file_name>:<line_number>[:<column_number>]
52+
SourceInfo ParseSymbolizerOutput(std::string Output) {
53+
SourceInfo Info;
54+
// Parse function name
55+
size_t End = Output.find_first_of('\n');
56+
assert(End != std::string::npos);
57+
Info.function = Output.substr(0, End);
58+
// Parse file name
59+
size_t Start = End + 1;
60+
End = Output.find_first_of(':', Start);
61+
assert(End != std::string::npos);
62+
Info.file = Output.substr(Start, End - Start);
63+
// Parse line number
64+
Start = End + 1;
65+
End = Output.find_first_of(":\n", Start);
66+
assert(End != std::string::npos);
67+
Info.line = std::stoi(Output.substr(Start, End - Start));
68+
// Parse column number if exists
69+
if (Output[End] == ':') {
70+
Start = End + 1;
71+
End = Output.find_first_of("\n", Start);
72+
assert(End != std::string::npos);
73+
Info.column = std::stoi(Output.substr(Start, End - Start));
74+
}
75+
76+
return Info;
77+
}
78+
2479
} // namespace
2580

2681
void StackTrace::print() const {
@@ -37,6 +92,26 @@ void StackTrace::print() const {
3792
Contains(BI, "libur_loader.so")) {
3893
continue;
3994
}
95+
96+
if (&SymbolizeCode != nullptr) {
97+
std::string Result;
98+
std::string ModuleName;
99+
uptr Offset;
100+
ParseBacktraceInfo(BI, ModuleName, Offset);
101+
if (SymbolizeCode(ModuleName, Offset, Result)) {
102+
SourceInfo SrcInfo = ParseSymbolizerOutput(Result);
103+
if (SrcInfo.file != "??") {
104+
getContext()->logger.always(" #{} in {} {}:{}:{}", index,
105+
SrcInfo.function, SrcInfo.file,
106+
SrcInfo.line, SrcInfo.column);
107+
} else {
108+
getContext()->logger.always(" #{} in {} ({}+{})", index,
109+
SrcInfo.function, ModuleName,
110+
(void *)Offset);
111+
}
112+
continue;
113+
}
114+
}
40115
getContext()->logger.always(" #{} {}", index, BI);
41116
++index;
42117
}

0 commit comments

Comments
 (0)