1 //===-- sanitizer_thread_history.cpp --------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "sanitizer_thread_history.h"
11 #include "sanitizer_stackdepot.h"
12 namespace __sanitizer
{
14 void PrintThreadHistory(ThreadRegistry
®istry
, InternalScopedString
&out
) {
15 ThreadRegistryLock
l(®istry
);
16 // Stack traces are largest part of printout and they often the same for
17 // multiple threads, so we will deduplicate them.
18 InternalMmapVector
<const ThreadContextBase
*> stacks
;
20 registry
.RunCallbackForEachThreadLocked(
21 [](ThreadContextBase
*context
, void *arg
) {
22 static_cast<decltype(&stacks
)>(arg
)->push_back(context
);
26 Sort(stacks
.data(), stacks
.size(),
27 [](const ThreadContextBase
*a
, const ThreadContextBase
*b
) {
28 if (a
->stack_id
< b
->stack_id
)
30 if (a
->stack_id
> b
->stack_id
)
32 return a
->unique_id
< b
->unique_id
;
35 auto describe_thread
= [&](const ThreadContextBase
*context
) {
40 out
.AppendF("T%llu/%llu", context
->unique_id
, context
->os_id
);
41 if (internal_strlen(context
->name
))
42 out
.AppendF(" (%s)", context
->name
);
46 [&](const ThreadContextBase
*context
) -> const ThreadContextBase
* {
49 ThreadContextBase
*parent
= registry
.GetThreadLocked(context
->parent_tid
);
52 if (parent
->unique_id
>= context
->unique_id
)
57 const ThreadContextBase
*prev
= nullptr;
58 for (const ThreadContextBase
*context
: stacks
) {
59 if (prev
&& prev
->stack_id
!= context
->stack_id
)
60 StackDepotGet(prev
->stack_id
).PrintTo(&out
);
62 out
.Append("Thread ");
63 describe_thread(context
);
64 out
.Append(" was created by ");
65 describe_thread(get_parent(context
));
69 StackDepotGet(prev
->stack_id
).PrintTo(&out
);
72 } // namespace __sanitizer