tsan_sync.cc revision 2d1fdb26e458c4ddc04155c1d421bced3ba90cd0
1603c4be006d8c53905d736bf1f19a49f5ce98276Alexey Samsonov//===-- tsan_sync.cc ------------------------------------------------------===//
27ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
37ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//                     The LLVM Compiler Infrastructure
47ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
57ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// This file is distributed under the University of Illinois Open Source
67ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// License. See LICENSE.TXT for details.
77ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
87ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//===----------------------------------------------------------------------===//
97ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
107ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// This file is a part of ThreadSanitizer (TSan), a race detector.
117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//===----------------------------------------------------------------------===//
1347b1634df012507799eb39aa17d4022d748ba67bAlexey Samsonov#include "sanitizer_common/sanitizer_placement_new.h"
147ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_sync.h"
157ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_rtl.h"
167ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_mman.h"
177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanynamespace __tsan {
197ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
202d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid DDMutexInit(ThreadState *thr, uptr pc, SyncVar *s);
212d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
22ad9da372f962495b3487685232d09390be841b1cDmitry VyukovSyncVar::SyncVar(uptr addr, u64 uid)
237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  : mtx(MutexTypeSyncVar, StatMtxSyncVar)
247ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  , addr(addr)
25ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  , uid(uid)
262d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  , creation_stack_id()
277ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  , owner_tid(kInvalidTid)
28332c62b52b3603be872b28bd3ea5e739aa28cd05Dmitry Vyukov  , last_lock()
297ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  , recursion()
307ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  , is_rw()
317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  , is_recursive()
322e933fc077595b18de37d2ed44e8f14c6053a432Dmitry Vyukov  , is_broken()
332e933fc077595b18de37d2ed44e8f14c6053a432Dmitry Vyukov  , is_linker_init() {
347ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
367ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanySyncTab::Part::Part()
377ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  : mtx(MutexTypeSyncTab, StatMtxSyncTab)
387ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  , val() {
397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
417ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanySyncTab::SyncTab() {
427ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
437ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
447ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanySyncTab::~SyncTab() {
457ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (int i = 0; i < kPartCount; i++) {
467ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    while (tab_[i].val) {
477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      SyncVar *tmp = tab_[i].val;
487ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      tab_[i].val = tmp->next;
497ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      DestroyAndFree(tmp);
507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    }
517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
537ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
54ad9da372f962495b3487685232d09390be841b1cDmitry VyukovSyncVar* SyncTab::GetOrCreateAndLock(ThreadState *thr, uptr pc,
55ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov                                     uptr addr, bool write_lock) {
56ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  return GetAndLock(thr, pc, addr, write_lock, true);
57ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov}
58ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov
59ad9da372f962495b3487685232d09390be841b1cDmitry VyukovSyncVar* SyncTab::GetIfExistsAndLock(uptr addr, bool write_lock) {
60ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  return GetAndLock(0, 0, addr, write_lock, false);
61ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov}
62ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov
6321cc85db95b8fa85a9ff7a403c8a24e345d73bafDmitry VyukovSyncVar* SyncTab::Create(ThreadState *thr, uptr pc, uptr addr) {
6421cc85db95b8fa85a9ff7a403c8a24e345d73bafDmitry Vyukov  StatInc(thr, StatSyncCreated);
6521cc85db95b8fa85a9ff7a403c8a24e345d73bafDmitry Vyukov  void *mem = internal_alloc(MBlockSync, sizeof(SyncVar));
6621cc85db95b8fa85a9ff7a403c8a24e345d73bafDmitry Vyukov  const u64 uid = atomic_fetch_add(&uid_gen_, 1, memory_order_relaxed);
6721cc85db95b8fa85a9ff7a403c8a24e345d73bafDmitry Vyukov  SyncVar *res = new(mem) SyncVar(addr, uid);
682d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  res->creation_stack_id = 0;
692d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (!kGoMode)  // Go does not use them
702d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    res->creation_stack_id = CurrentStackId(thr, pc);
712d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (flags()->detect_deadlocks)
722d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    DDMutexInit(thr, pc, res);
7321cc85db95b8fa85a9ff7a403c8a24e345d73bafDmitry Vyukov  return res;
7421cc85db95b8fa85a9ff7a403c8a24e345d73bafDmitry Vyukov}
7521cc85db95b8fa85a9ff7a403c8a24e345d73bafDmitry Vyukov
767ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanySyncVar* SyncTab::GetAndLock(ThreadState *thr, uptr pc,
77ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov                             uptr addr, bool write_lock, bool create) {
789bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov#ifndef TSAN_GO
7921cc85db95b8fa85a9ff7a403c8a24e345d73bafDmitry Vyukov  {  // NOLINT
8021cc85db95b8fa85a9ff7a403c8a24e345d73bafDmitry Vyukov    SyncVar *res = GetJavaSync(thr, pc, addr, write_lock, create);
8121cc85db95b8fa85a9ff7a403c8a24e345d73bafDmitry Vyukov    if (res)
8221cc85db95b8fa85a9ff7a403c8a24e345d73bafDmitry Vyukov      return res;
8321cc85db95b8fa85a9ff7a403c8a24e345d73bafDmitry Vyukov  }
8421cc85db95b8fa85a9ff7a403c8a24e345d73bafDmitry Vyukov
854554b7a7b345cd50ff8138b3cda8dd1135b965faDmitry Vyukov  // Here we ask only PrimaryAllocator, because
864554b7a7b345cd50ff8138b3cda8dd1135b965faDmitry Vyukov  // SecondaryAllocator::PointerIsMine() is slow and we have fallback on
874554b7a7b345cd50ff8138b3cda8dd1135b965faDmitry Vyukov  // the hashmap anyway.
889bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov  if (PrimaryAllocator::PointerIsMine((void*)addr)) {
899bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov    MBlock *b = user_mblock(thr, (void*)addr);
9003049413f8978c202a254eb0acfa2f10b9bbe34aDmitry Vyukov    CHECK_NE(b, 0);
91f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov    MBlock::ScopedLock l(b);
929bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov    SyncVar *res = 0;
93f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov    for (res = b->ListHead(); res; res = res->next) {
949bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov      if (res->addr == addr)
959bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov        break;
969bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov    }
979bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov    if (res == 0) {
98ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      if (!create)
99ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov        return 0;
10021cc85db95b8fa85a9ff7a403c8a24e345d73bafDmitry Vyukov      res = Create(thr, pc, addr);
101f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov      b->ListPush(res);
1029bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov    }
1039bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov    if (write_lock)
1049bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov      res->mtx.Lock();
1059bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov    else
1069bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov      res->mtx.ReadLock();
1079bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov    return res;
1089bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov  }
1099bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov#endif
1109bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov
1117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  Part *p = &tab_[PartIdx(addr)];
1127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  {
1137ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    ReadLock l(&p->mtx);
1147ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    for (SyncVar *res = p->val; res; res = res->next) {
1157ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      if (res->addr == addr) {
1167ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        if (write_lock)
1177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany          res->mtx.Lock();
1187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        else
1197ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany          res->mtx.ReadLock();
1207ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        return res;
1217ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      }
1227ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    }
1237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
124ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  if (!create)
125ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    return 0;
1267ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  {
1277ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    Lock l(&p->mtx);
1287ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    SyncVar *res = p->val;
1297ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    for (; res; res = res->next) {
1307ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      if (res->addr == addr)
1317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        break;
1327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    }
1337ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (res == 0) {
13421cc85db95b8fa85a9ff7a403c8a24e345d73bafDmitry Vyukov      res = Create(thr, pc, addr);
1357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      res->next = p->val;
1367ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      p->val = res;
1377ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    }
1387ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (write_lock)
1397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      res->mtx.Lock();
1407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    else
1417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      res->mtx.ReadLock();
1427ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return res;
1437ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
1447ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1457ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1467ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanySyncVar* SyncTab::GetAndRemove(ThreadState *thr, uptr pc, uptr addr) {
1479bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov#ifndef TSAN_GO
14821cc85db95b8fa85a9ff7a403c8a24e345d73bafDmitry Vyukov  {  // NOLINT
14921cc85db95b8fa85a9ff7a403c8a24e345d73bafDmitry Vyukov    SyncVar *res = GetAndRemoveJavaSync(thr, pc, addr);
15021cc85db95b8fa85a9ff7a403c8a24e345d73bafDmitry Vyukov    if (res)
15121cc85db95b8fa85a9ff7a403c8a24e345d73bafDmitry Vyukov      return res;
15221cc85db95b8fa85a9ff7a403c8a24e345d73bafDmitry Vyukov  }
1539bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov  if (PrimaryAllocator::PointerIsMine((void*)addr)) {
1549bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov    MBlock *b = user_mblock(thr, (void*)addr);
15503049413f8978c202a254eb0acfa2f10b9bbe34aDmitry Vyukov    CHECK_NE(b, 0);
1569bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov    SyncVar *res = 0;
1579bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov    {
158f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov      MBlock::ScopedLock l(b);
159f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov      res = b->ListHead();
160f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov      if (res) {
1619bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov        if (res->addr == addr) {
16255e711ed818d7553d62eba4b3a2fad3e2723f697Dmitry Vyukov          if (res->is_linker_init)
16355e711ed818d7553d62eba4b3a2fad3e2723f697Dmitry Vyukov            return 0;
164f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov          b->ListPop();
165f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov        } else {
166f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov          SyncVar **prev = &res->next;
167f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov          res = *prev;
168f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov          while (res) {
169f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov            if (res->addr == addr) {
170f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov              if (res->is_linker_init)
171f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov                return 0;
172f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov              *prev = res->next;
173f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov              break;
174f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov            }
175f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov            prev = &res->next;
176f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov            res = *prev;
177f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov          }
178f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov        }
179f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov        if (res) {
180f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov          StatInc(thr, StatSyncDestroyed);
181f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov          res->mtx.Lock();
182f51c3860ce0a1ae81d0dc9da27db0693718db18eDmitry Vyukov          res->mtx.Unlock();
1839bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov        }
1849bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov      }
1859bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov    }
1869bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov    return res;
1879bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov  }
1889bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov#endif
1899bbc579e11900741551b81b5e91d22ca47d70b26Dmitry Vyukov
1907ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  Part *p = &tab_[PartIdx(addr)];
1917ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  SyncVar *res = 0;
1927ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  {
1937ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    Lock l(&p->mtx);
1947ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    SyncVar **prev = &p->val;
1957ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    res = *prev;
1967ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    while (res) {
1977ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      if (res->addr == addr) {
19855e711ed818d7553d62eba4b3a2fad3e2723f697Dmitry Vyukov        if (res->is_linker_init)
19955e711ed818d7553d62eba4b3a2fad3e2723f697Dmitry Vyukov          return 0;
2007ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        *prev = res->next;
2017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany        break;
2027ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      }
2037ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      prev = &res->next;
2047ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany      res = *prev;
2057ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    }
2067ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
2077ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (res) {
2087ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    StatInc(thr, StatSyncDestroyed);
2097ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    res->mtx.Lock();
2107ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    res->mtx.Unlock();
2117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
2127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return res;
2137ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2147ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2157ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyint SyncTab::PartIdx(uptr addr) {
2167ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return (addr >> 3) % kPartCount;
2177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2197ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyStackTrace::StackTrace()
2207ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    : n_()
2219ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov    , s_()
2229ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov    , c_() {
2239ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov}
2249ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov
2259ad7c32720dfa1287f8cfd481e5d583435178caeDmitry VyukovStackTrace::StackTrace(uptr *buf, uptr cnt)
2269ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov    : n_()
2279ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov    , s_(buf)
2289ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov    , c_(cnt) {
2299ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov  CHECK_NE(buf, 0);
2309ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov  CHECK_NE(cnt, 0);
2317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2337ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyStackTrace::~StackTrace() {
2347ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  Reset();
2357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2367ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2377ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid StackTrace::Reset() {
2389ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov  if (s_ && !c_) {
2397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    CHECK_NE(n_, 0);
2407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    internal_free(s_);
2417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    s_ = 0;
2427ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
2439ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov  n_ = 0;
2447ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2457ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2467ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid StackTrace::Init(const uptr *pcs, uptr cnt) {
2477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  Reset();
2487ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (cnt == 0)
2497ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
2509ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov  if (c_) {
2519ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov    CHECK_NE(s_, 0);
2529ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov    CHECK_LE(cnt, c_);
2539ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov  } else {
2549ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov    s_ = (uptr*)internal_alloc(MBlockStackTrace, cnt * sizeof(s_[0]));
2559ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov  }
2567ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  n_ = cnt;
2579ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov  internal_memcpy(s_, pcs, cnt * sizeof(s_[0]));
2587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2597ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2607ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid StackTrace::ObtainCurrent(ThreadState *thr, uptr toppc) {
2617ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  Reset();
26225d1c799087af5757ab6efc4a77558565fb1744aDmitry Vyukov  n_ = thr->shadow_stack_pos - thr->shadow_stack;
2637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (n_ + !!toppc == 0)
2647ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
2650ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukov  uptr start = 0;
2669ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov  if (c_) {
2679ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov    CHECK_NE(s_, 0);
2680ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukov    if (n_ + !!toppc > c_) {
2690ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukov      start = n_ - c_ + !!toppc;
2700ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukov      n_ = c_ - !!toppc;
2710ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukov    }
2729ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov  } else {
27301a7ce809bf7cc627d73c045c70bcca9891f632cDmitry Vyukov    // Cap potentially huge stacks.
27401a7ce809bf7cc627d73c045c70bcca9891f632cDmitry Vyukov    if (n_ + !!toppc > kTraceStackSize) {
27501a7ce809bf7cc627d73c045c70bcca9891f632cDmitry Vyukov      start = n_ - kTraceStackSize + !!toppc;
27601a7ce809bf7cc627d73c045c70bcca9891f632cDmitry Vyukov      n_ = kTraceStackSize - !!toppc;
27701a7ce809bf7cc627d73c045c70bcca9891f632cDmitry Vyukov    }
2789ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov    s_ = (uptr*)internal_alloc(MBlockStackTrace,
2799ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov                               (n_ + !!toppc) * sizeof(s_[0]));
2809ad7c32720dfa1287f8cfd481e5d583435178caeDmitry Vyukov  }
2817ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < n_; i++)
2820ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukov    s_[i] = thr->shadow_stack[start + i];
2837ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (toppc) {
2847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    s_[n_] = toppc;
2857ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    n_++;
2867ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
2877ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid StackTrace::CopyFrom(const StackTrace& other) {
2907ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  Reset();
2917ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  Init(other.Begin(), other.Size());
2927ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2937ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2947ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanybool StackTrace::IsEmpty() const {
2957ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return n_ == 0;
2967ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2977ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2987ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyuptr StackTrace::Size() const {
2997ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return n_;
3007ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
3017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
3027ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyuptr StackTrace::Get(uptr i) const {
3037ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  CHECK_LT(i, n_);
3047ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return s_[i];
3057ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
3067ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
3077ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyconst uptr *StackTrace::Begin() const {
3087ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  return s_;
3097ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
3107ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
3117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}  // namespace __tsan
312