1//===-- sanitizer_thread_history.cpp --------------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
9#include "sanitizer_thread_history.h"
10
11#include "sanitizer_stackdepot.h"
12namespace __sanitizer {
13
14void PrintThreadHistory(ThreadRegistry &registry, InternalScopedString &out) {
15 ThreadRegistryLock l(&registry);
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;
19
20 registry.RunCallbackForEachThreadLocked(
21 cb: [](ThreadContextBase *context, void *arg) {
22 static_cast<decltype(&stacks)>(arg)->push_back(element: context);
23 },
24 arg: &stacks);
25
26 Sort(v: stacks.data(), size: stacks.size(),
27 comp: [](const ThreadContextBase *a, const ThreadContextBase *b) {
28 if (a->stack_id < b->stack_id)
29 return true;
30 if (a->stack_id > b->stack_id)
31 return false;
32 return a->unique_id < b->unique_id;
33 });
34
35 auto describe_thread = [&](const ThreadContextBase *context) {
36 if (!context) {
37 out.Append(str: "T-1");
38 return;
39 }
40 out.AppendF(format: "T%llu/%llu", context->unique_id, context->os_id);
41 if (internal_strlen(s: context->name))
42 out.AppendF(format: " (%s)", context->name);
43 };
44
45 auto get_parent =
46 [&](const ThreadContextBase *context) -> const ThreadContextBase * {
47 if (!context)
48 return nullptr;
49 ThreadContextBase *parent = registry.GetThreadLocked(tid: context->parent_tid);
50 if (!parent)
51 return nullptr;
52 if (parent->unique_id >= context->unique_id)
53 return nullptr;
54 return parent;
55 };
56
57 const ThreadContextBase *prev = nullptr;
58 for (const ThreadContextBase *context : stacks) {
59 if (prev && prev->stack_id != context->stack_id)
60 StackDepotGet(id: prev->stack_id).PrintTo(output: &out);
61 prev = context;
62 out.Append(str: "Thread ");
63 describe_thread(context);
64 out.Append(str: " was created by ");
65 describe_thread(get_parent(context));
66 out.Append(str: "\n");
67 }
68 if (prev)
69 StackDepotGet(id: prev->stack_id).PrintTo(output: &out);
70}
71
72} // namespace __sanitizer
73