master
 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      [](ThreadContextBase *context, void *arg) {
22        static_cast<decltype(&stacks)>(arg)->push_back(context);
23      },
24      &stacks);
25
26  Sort(stacks.data(), stacks.size(),
27       [](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("T-1");
38      return;
39    }
40    out.AppendF("T%llu/%llu", context->unique_id, context->os_id);
41    if (internal_strlen(context->name))
42      out.AppendF(" (%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(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(prev->stack_id).PrintTo(&out);
61    prev = context;
62    out.Append("Thread ");
63    describe_thread(context);
64    out.Append(" was created by ");
65    describe_thread(get_parent(context));
66    out.Append("\n");
67  }
68  if (prev)
69    StackDepotGet(prev->stack_id).PrintTo(&out);
70}
71
72}  // namespace __sanitizer