Skip to content

Commit d5bc700

Browse files
zhaomaosuomarahmed1111
authored andcommitted
[DeviceSanitizer] Implement symbolizer for more readable information
1 parent a985a81 commit d5bc700

File tree

5 files changed

+145
-4
lines changed

5 files changed

+145
-4
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: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,50 @@
1212
#include <execinfo.h>
1313
#include <string>
1414

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

24+
std::string ExtractModuleName(const char *Symbol) {
25+
auto s1 = std::strrchr(Symbol, '(');
26+
return std::string(Symbol, s1 - Symbol);
27+
}
28+
29+
// Parse symbolizer output in the following formats:
30+
// <function_name>
31+
// <file_name>:<line_number>[:<column_number>]
32+
SourceInfo ParseSymbolizerOutput(std::string Output) {
33+
SourceInfo Info;
34+
// Parse function name
35+
size_t End = Output.find_first_of('\n');
36+
assert(End != std::string::npos);
37+
Info.function = Output.substr(0, End);
38+
// Parse file name
39+
size_t Start = End + 1;
40+
End = Output.find_first_of(':', Start);
41+
assert(End != std::string::npos);
42+
Info.file = Output.substr(Start, End - Start);
43+
// Parse line number
44+
Start = End + 1;
45+
End = Output.find_first_of(":\n", Start);
46+
assert(End != std::string::npos);
47+
Info.line = std::stoi(Output.substr(Start, End - Start));
48+
// Parse column number if exists
49+
if (Output[End] == ':') {
50+
Start = End + 1;
51+
End = Output.find_first_of("\n", Start);
52+
assert(End != std::string::npos);
53+
Info.column = std::stoi(Output.substr(Start, End - Start));
54+
}
55+
56+
return Info;
57+
}
58+
1759
StackTrace GetCurrentBacktrace() {
1860
void *Frames[MAX_BACKTRACE_FRAMES];
1961
int FrameCount = backtrace(Frames, MAX_BACKTRACE_FRAMES);
@@ -25,8 +67,24 @@ StackTrace GetCurrentBacktrace() {
2567

2668
StackTrace Stack;
2769
for (int i = 0; i < FrameCount; i++) {
28-
BacktraceInfo addr_info(Symbols[i]);
29-
Stack.stack.emplace_back(std::move(addr_info));
70+
if (SymbolizeCode != nullptr) {
71+
std::string Result;
72+
std::string ModuleName = ExtractModuleName(Symbols[i]);
73+
if (SymbolizeCode(ModuleName, (uint64_t)Frames[i], Result)) {
74+
SourceInfo SrcInfo = ParseSymbolizerOutput(Result);
75+
std::ostringstream OS;
76+
if (SrcInfo.file != "??") {
77+
OS << "in " << SrcInfo.function << " " << SrcInfo.file
78+
<< ":" << SrcInfo.line << ":" << SrcInfo.column;
79+
} else {
80+
OS << "in " << SrcInfo.function << " (" << ModuleName << "+"
81+
<< Frames[i] << ")";
82+
}
83+
Stack.stack.emplace_back(OS.str());
84+
continue;
85+
}
86+
}
87+
Stack.stack.emplace_back(Symbols[i]);
3088
}
3189
free(Symbols);
3290

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+
}

0 commit comments

Comments
 (0)