Skip to content

[DeviceSanitizer] Implement symbolizer for more readable information #1844

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
cmake_minimum_required(VERSION 3.20.0 FATAL_ERROR)
project(unified-runtime VERSION 0.10.0)

# Check if unified runtime is built as a standalone project.
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR UR_STANDALONE_BUILD)
set(UR_STANDALONE_BUILD TRUE)
endif()

include(GNUInstallDirs)
include(CheckCXXSourceCompiles)
include(CMakePackageConfigHelpers)
Expand Down Expand Up @@ -37,6 +42,7 @@ option(UR_USE_MSAN "enable MemorySanitizer" OFF)
option(UR_USE_TSAN "enable ThreadSanitizer" OFF)
option(UR_ENABLE_TRACING "enable api tracing through xpti" OFF)
option(UR_ENABLE_SANITIZER "enable device sanitizer" ON)
option(UR_ENABLE_SYMBOLIZER "enable symoblizer for sanitizer" OFF)
option(UMF_BUILD_SHARED_LIBRARY "Build UMF as shared library" ON)
option(UMF_ENABLE_POOL_TRACKING "Build UMF with pool tracking" ON)
option(UR_BUILD_ADAPTER_L0 "Build the Level-Zero adapter" OFF)
Expand Down Expand Up @@ -163,6 +169,14 @@ if(UR_ENABLE_SANITIZER)
else()
add_compile_definitions(UR_ENABLE_SANITIZER)
endif()

if(UR_ENABLE_SYMBOLIZER AND UR_STANDALONE_BUILD)
find_package(LLVM REQUIRED)
endif()
else()
if(UR_ENABLE_SYMBOLIZER)
message(FATAL_ERROR "Symbolizer must be enabled with Sanitizer layer")
endif()
endif()

if(UR_USE_ASAN)
Expand Down
9 changes: 9 additions & 0 deletions source/loader/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,15 @@ if(UR_ENABLE_SANITIZER)
${CMAKE_CURRENT_SOURCE_DIR}/layers/sanitizer/linux/sanitizer_utils.cpp
)

if(UR_ENABLE_SYMBOLIZER)
target_sources(ur_loader
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/layers/sanitizer/linux/symbolizer.cpp
)
target_include_directories(ur_loader PRIVATE ${LLVM_INCLUDE_DIRS})
target_link_libraries(ur_loader PRIVATE LLVMSymbolize)
endif()

target_include_directories(ur_loader PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/layers/sanitizer"
"${CMAKE_CURRENT_SOURCE_DIR}/../"
Expand Down
4 changes: 2 additions & 2 deletions source/loader/layers/sanitizer/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ using BacktraceInfo = std::string;
struct SourceInfo {
std::string file;
std::string function;
int line;
int column;
int line = 0;
int column = 0;
};

enum class DeviceType : uint64_t { UNKNOWN = 0, CPU, GPU_PVC, GPU_DG2 };
Expand Down
2 changes: 1 addition & 1 deletion source/loader/layers/sanitizer/linux/backtrace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ StackTrace GetCurrentBacktrace() {
StackTrace Stack;
for (int i = 0; i < FrameCount; i++) {
BacktraceInfo addr_info(Symbols[i]);
Stack.stack.emplace_back(std::move(addr_info));
Stack.stack.emplace_back(addr_info);
}
free(Symbols);

Expand Down
60 changes: 60 additions & 0 deletions source/loader/layers/sanitizer/linux/symbolizer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
*
* Copyright (C) 2024 Intel Corporation
*
* Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM Exceptions.
* See LICENSE.TXT
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*
*/
#include "llvm/DebugInfo/Symbolize/DIPrinter.h"
#include "llvm/DebugInfo/Symbolize/Symbolize.h"

namespace ur_sanitizer_layer {

llvm::symbolize::LLVMSymbolizer *GetSymbolizer() {
static llvm::symbolize::LLVMSymbolizer Symbolizer;
return &Symbolizer;
}

llvm::symbolize::PrinterConfig GetPrinterConfig() {
llvm::symbolize::PrinterConfig Config;
Config.Pretty = false;
Config.PrintAddress = false;
Config.PrintFunctions = true;
Config.SourceContextLines = 0;
Config.Verbose = false;
return Config;
}

} // namespace ur_sanitizer_layer

extern "C" {

bool SymbolizeCode(const std::string ModuleName, uint64_t ModuleOffset,
std::string &Result) {
llvm::raw_string_ostream OS(Result);
llvm::symbolize::Request Request{ModuleName, ModuleOffset};
llvm::symbolize::PrinterConfig Config =
ur_sanitizer_layer::GetPrinterConfig();
llvm::symbolize::ErrorHandler EH = [&](const llvm::ErrorInfoBase &ErrorInfo,
llvm::StringRef ErrorBanner) {
OS << ErrorBanner;
ErrorInfo.log(OS);
OS << '\n';
};
auto Printer =
std::make_unique<llvm::symbolize::LLVMPrinter>(OS, EH, Config);

auto ResOrErr = ur_sanitizer_layer::GetSymbolizer()->symbolizeInlinedCode(
ModuleName,
{ModuleOffset, llvm::object::SectionedAddress::UndefSection});

if (!ResOrErr) {
return false;
}
Printer->print(Request, *ResOrErr);
ur_sanitizer_layer::GetSymbolizer()->pruneCache();
return true;
}
}
75 changes: 75 additions & 0 deletions source/loader/layers/sanitizer/stacktrace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@
#include "stacktrace.hpp"
#include "ur_sanitizer_layer.hpp"

extern "C" {

__attribute__((weak)) bool SymbolizeCode(const std::string ModuleName,
uint64_t ModuleOffset,
std::string &Result);
}

namespace ur_sanitizer_layer {

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

// Parse back trace information in the following formats:
// <module_name>([function_name]+function_offset) [offset]
void ParseBacktraceInfo(BacktraceInfo BI, std::string &ModuleName,
uptr &Offset) {
// Parse module name
size_t End = BI.find_first_of('(');
assert(End != std::string::npos);
ModuleName = BI.substr(0, End);
// Parse offset
size_t Start = BI.find_first_of('[');
assert(Start != std::string::npos);
Start = BI.substr(Start + 1, 2) == "0x" ? Start + 3 : Start + 1;
End = BI.find_first_of(']');
assert(End != std::string::npos);
Offset = std::stoull(BI.substr(Start, End), nullptr, 16);
return;
}

// Parse symbolizer output in the following formats:
// <function_name>
// <file_name>:<line_number>[:<column_number>]
SourceInfo ParseSymbolizerOutput(std::string Output) {
SourceInfo Info;
// Parse function name
size_t End = Output.find_first_of('\n');
assert(End != std::string::npos);
Info.function = Output.substr(0, End);
// Parse file name
size_t Start = End + 1;
End = Output.find_first_of(':', Start);
assert(End != std::string::npos);
Info.file = Output.substr(Start, End - Start);
// Parse line number
Start = End + 1;
End = Output.find_first_of(":\n", Start);
assert(End != std::string::npos);
Info.line = std::stoi(Output.substr(Start, End - Start));
// Parse column number if exists
if (Output[End] == ':') {
Start = End + 1;
End = Output.find_first_of("\n", Start);
assert(End != std::string::npos);
Info.column = std::stoi(Output.substr(Start, End - Start));
}

return Info;
}

} // namespace

void StackTrace::print() const {
Expand All @@ -37,6 +92,26 @@ void StackTrace::print() const {
Contains(BI, "libur_loader.so")) {
continue;
}

if (&SymbolizeCode != nullptr) {
std::string Result;
std::string ModuleName;
uptr Offset;
ParseBacktraceInfo(BI, ModuleName, Offset);
if (SymbolizeCode(ModuleName, Offset, Result)) {
SourceInfo SrcInfo = ParseSymbolizerOutput(Result);
if (SrcInfo.file != "??") {
getContext()->logger.always(" #{} in {} {}:{}:{}", index,
SrcInfo.function, SrcInfo.file,
SrcInfo.line, SrcInfo.column);
} else {
getContext()->logger.always(" #{} in {} ({}+{})", index,
SrcInfo.function, ModuleName,
(void *)Offset);
}
continue;
}
}
getContext()->logger.always(" #{} {}", index, BI);
++index;
}
Expand Down
Loading