1//===-- tsan_stack_trace.cc -----------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of ThreadSanitizer (TSan), a race detector.
11//
12//===----------------------------------------------------------------------===//
13//#include "sanitizer_common/sanitizer_placement_new.h"
14#include "tsan_stack_trace.h"
15#include "tsan_rtl.h"
16#include "tsan_mman.h"
17
18namespace __tsan {
19
20StackTrace::StackTrace()
21    : n_()
22    , s_()
23    , c_() {
24}
25
26StackTrace::StackTrace(uptr *buf, uptr cnt)
27    : n_()
28    , s_(buf)
29    , c_(cnt) {
30  CHECK_NE(buf, 0);
31  CHECK_NE(cnt, 0);
32}
33
34StackTrace::~StackTrace() {
35  Reset();
36}
37
38void StackTrace::Reset() {
39  if (s_ && !c_) {
40    CHECK_NE(n_, 0);
41    internal_free(s_);
42    s_ = 0;
43  }
44  n_ = 0;
45}
46
47void StackTrace::Init(const uptr *pcs, uptr cnt) {
48  Reset();
49  if (cnt == 0)
50    return;
51  if (c_) {
52    CHECK_NE(s_, 0);
53    CHECK_LE(cnt, c_);
54  } else {
55    s_ = (uptr*)internal_alloc(MBlockStackTrace, cnt * sizeof(s_[0]));
56  }
57  n_ = cnt;
58  internal_memcpy(s_, pcs, cnt * sizeof(s_[0]));
59}
60
61void StackTrace::ObtainCurrent(ThreadState *thr, uptr toppc) {
62  Reset();
63  n_ = thr->shadow_stack_pos - thr->shadow_stack;
64  if (n_ + !!toppc == 0)
65    return;
66  uptr start = 0;
67  if (c_) {
68    CHECK_NE(s_, 0);
69    if (n_ + !!toppc > c_) {
70      start = n_ - c_ + !!toppc;
71      n_ = c_ - !!toppc;
72    }
73  } else {
74    // Cap potentially huge stacks.
75    if (n_ + !!toppc > kTraceStackSize) {
76      start = n_ - kTraceStackSize + !!toppc;
77      n_ = kTraceStackSize - !!toppc;
78    }
79    s_ = (uptr*)internal_alloc(MBlockStackTrace,
80                               (n_ + !!toppc) * sizeof(s_[0]));
81  }
82  for (uptr i = 0; i < n_; i++)
83    s_[i] = thr->shadow_stack[start + i];
84  if (toppc) {
85    s_[n_] = toppc;
86    n_++;
87  }
88}
89
90void StackTrace::CopyFrom(const StackTrace& other) {
91  Reset();
92  Init(other.Begin(), other.Size());
93}
94
95bool StackTrace::IsEmpty() const {
96  return n_ == 0;
97}
98
99uptr StackTrace::Size() const {
100  return n_;
101}
102
103uptr StackTrace::Get(uptr i) const {
104  CHECK_LT(i, n_);
105  return s_[i];
106}
107
108const uptr *StackTrace::Begin() const {
109  return s_;
110}
111
112}  // namespace __tsan
113