mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-26 20:56:07 +00:00
[NFC][sanitizer] Add Debug utility to print thread history (#111948)
For #111949
This commit is contained in:
parent
e1cff8bf81
commit
aa44f59abf
@ -94,6 +94,7 @@ set(SANITIZER_SYMBOLIZER_SOURCES
|
|||||||
sanitizer_symbolizer_report.cpp
|
sanitizer_symbolizer_report.cpp
|
||||||
sanitizer_symbolizer_report_fuchsia.cpp
|
sanitizer_symbolizer_report_fuchsia.cpp
|
||||||
sanitizer_symbolizer_win.cpp
|
sanitizer_symbolizer_win.cpp
|
||||||
|
sanitizer_thread_history.cpp
|
||||||
sanitizer_unwind_linux_libcdep.cpp
|
sanitizer_unwind_linux_libcdep.cpp
|
||||||
sanitizer_unwind_fuchsia.cpp
|
sanitizer_unwind_fuchsia.cpp
|
||||||
sanitizer_unwind_win.cpp
|
sanitizer_unwind_win.cpp
|
||||||
|
@ -0,0 +1,72 @@
|
|||||||
|
//===-- sanitizer_thread_history.cpp --------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "sanitizer_thread_history.h"
|
||||||
|
|
||||||
|
#include "sanitizer_stackdepot.h"
|
||||||
|
namespace __sanitizer {
|
||||||
|
|
||||||
|
void PrintThreadHistory(ThreadRegistry ®istry, InternalScopedString &out) {
|
||||||
|
ThreadRegistryLock l(®istry);
|
||||||
|
// Stack traces are largest part of printout and they often the same for
|
||||||
|
// multiple threads, so we will deduplicate them.
|
||||||
|
InternalMmapVector<const ThreadContextBase *> stacks;
|
||||||
|
|
||||||
|
registry.RunCallbackForEachThreadLocked(
|
||||||
|
[](ThreadContextBase *context, void *arg) {
|
||||||
|
static_cast<decltype(&stacks)>(arg)->push_back(context);
|
||||||
|
},
|
||||||
|
&stacks);
|
||||||
|
|
||||||
|
Sort(stacks.data(), stacks.size(),
|
||||||
|
[](const ThreadContextBase *a, const ThreadContextBase *b) {
|
||||||
|
if (a->stack_id < b->stack_id)
|
||||||
|
return true;
|
||||||
|
if (a->stack_id > b->stack_id)
|
||||||
|
return false;
|
||||||
|
return a->unique_id < b->unique_id;
|
||||||
|
});
|
||||||
|
|
||||||
|
auto describe_thread = [&](const ThreadContextBase *context) {
|
||||||
|
if (!context) {
|
||||||
|
out.Append("T-1");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
out.AppendF("T%llu/%llu", context->unique_id, context->os_id);
|
||||||
|
if (internal_strlen(context->name))
|
||||||
|
out.AppendF(" (%s)", context->name);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto get_parent =
|
||||||
|
[&](const ThreadContextBase *context) -> const ThreadContextBase * {
|
||||||
|
if (!context)
|
||||||
|
return nullptr;
|
||||||
|
ThreadContextBase *parent = registry.GetThreadLocked(context->parent_tid);
|
||||||
|
if (!parent)
|
||||||
|
return nullptr;
|
||||||
|
if (parent->unique_id >= context->unique_id)
|
||||||
|
return nullptr;
|
||||||
|
return parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ThreadContextBase *prev = nullptr;
|
||||||
|
for (const ThreadContextBase *context : stacks) {
|
||||||
|
if (prev && prev->stack_id != context->stack_id)
|
||||||
|
StackDepotGet(prev->stack_id).PrintTo(&out);
|
||||||
|
prev = context;
|
||||||
|
out.Append("Thread ");
|
||||||
|
describe_thread(context);
|
||||||
|
out.Append(" was created by ");
|
||||||
|
describe_thread(get_parent(context));
|
||||||
|
out.Append("\n");
|
||||||
|
}
|
||||||
|
if (prev)
|
||||||
|
StackDepotGet(prev->stack_id).PrintTo(&out);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace __sanitizer
|
24
compiler-rt/lib/sanitizer_common/sanitizer_thread_history.h
Normal file
24
compiler-rt/lib/sanitizer_common/sanitizer_thread_history.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
//===-- sanitizer_thread_history.h ------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Utility to print thread histroy from ThreadRegistry.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef SANITIZER_THREAD_HISTORY_H
|
||||||
|
#define SANITIZER_THREAD_HISTORY_H
|
||||||
|
|
||||||
|
#include "sanitizer_thread_registry.h"
|
||||||
|
|
||||||
|
namespace __sanitizer {
|
||||||
|
|
||||||
|
void PrintThreadHistory(ThreadRegistry& registry, InternalScopedString& out);
|
||||||
|
|
||||||
|
} // namespace __sanitizer
|
||||||
|
|
||||||
|
#endif // SANITIZER_THREAD_HISTORY_H
|
@ -11,11 +11,19 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
#include "sanitizer_common/sanitizer_thread_registry.h"
|
#include "sanitizer_common/sanitizer_thread_registry.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "gmock/gmock.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
#include "sanitizer_common/sanitizer_common.h"
|
||||||
|
#include "sanitizer_common/sanitizer_stackdepot.h"
|
||||||
|
#include "sanitizer_common/sanitizer_stacktrace.h"
|
||||||
|
#include "sanitizer_common/sanitizer_thread_history.h"
|
||||||
#include "sanitizer_pthread_wrappers.h"
|
#include "sanitizer_pthread_wrappers.h"
|
||||||
|
|
||||||
|
using testing::HasSubstr;
|
||||||
|
|
||||||
namespace __sanitizer {
|
namespace __sanitizer {
|
||||||
|
|
||||||
static Mutex tctx_allocator_lock;
|
static Mutex tctx_allocator_lock;
|
||||||
@ -239,4 +247,56 @@ TEST(SanitizerCommon, ThreadRegistryThreadedTest) {
|
|||||||
ThreadedTestRegistry(®istry);
|
ThreadedTestRegistry(®istry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(SanitizerCommon, PrintThreadHistory) {
|
||||||
|
ThreadRegistry registry(GetThreadContext<TestThreadContext>,
|
||||||
|
kThreadsPerShard * kNumShards + 1, 10, 0);
|
||||||
|
|
||||||
|
UNINITIALIZED BufferedStackTrace stack1;
|
||||||
|
stack1.Unwind(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), nullptr, false,
|
||||||
|
/*max_depth=*/1);
|
||||||
|
|
||||||
|
UNINITIALIZED BufferedStackTrace stack2;
|
||||||
|
stack2.Unwind(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), nullptr, false,
|
||||||
|
/*max_depth=*/1);
|
||||||
|
|
||||||
|
EXPECT_EQ(0U, registry.CreateThread(0, true, -1, 0, nullptr));
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
registry.CreateThread(0, true, 0, StackDepotPut(stack1), nullptr);
|
||||||
|
registry.CreateThread(0, true, 0, StackDepotPut(stack2), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
InternalScopedString out;
|
||||||
|
PrintThreadHistory(registry, out);
|
||||||
|
|
||||||
|
std::string substrings[] = {
|
||||||
|
"Thread T0/0 was created by T-1",
|
||||||
|
"<empty stack>",
|
||||||
|
"",
|
||||||
|
"Thread T1/0 was created by T0/0",
|
||||||
|
"Thread T3/0 was created by T0/0",
|
||||||
|
"Thread T5/0 was created by T0/0",
|
||||||
|
"Thread T7/0 was created by T0/0",
|
||||||
|
"Thread T9/0 was created by T0/0",
|
||||||
|
"#0 0x",
|
||||||
|
"",
|
||||||
|
"Thread T2/0 was created by T0/0",
|
||||||
|
"Thread T4/0 was created by T0/0",
|
||||||
|
"Thread T6/0 was created by T0/0",
|
||||||
|
"Thread T8/0 was created by T0/0",
|
||||||
|
"Thread T10/0 was created by T0/0",
|
||||||
|
"#0 0x",
|
||||||
|
"",
|
||||||
|
};
|
||||||
|
|
||||||
|
std::stringstream ss(out.data());
|
||||||
|
std::string line;
|
||||||
|
|
||||||
|
for (auto substr : substrings) {
|
||||||
|
std::getline(ss, line);
|
||||||
|
EXPECT_THAT(line, HasSubstr(substr)) << line;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_FALSE(std::getline(ss, line)) << "Unmatched line: " << line;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace __sanitizer
|
} // namespace __sanitizer
|
||||||
|
Loading…
x
Reference in New Issue
Block a user