1//===-- sanitizer_symbolizer.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// This file is shared between AddressSanitizer and ThreadSanitizer
10// run-time libraries.
11//===----------------------------------------------------------------------===//
12
13#include <errno.h>
14
15#include "sanitizer_allocator_internal.h"
16#include "sanitizer_common.h"
17#include "sanitizer_internal_defs.h"
18#include "sanitizer_libc.h"
19#include "sanitizer_placement_new.h"
20#include "sanitizer_platform.h"
21#include "sanitizer_symbolizer_internal.h"
22
23namespace __sanitizer {
24
25AddressInfo::AddressInfo() {
26  internal_memset(this, 0, sizeof(AddressInfo));
27  function_offset = kUnknown;
28}
29
30void AddressInfo::Clear() {
31  InternalFree(module);
32  InternalFree(function);
33  InternalFree(file);
34  internal_memset(this, 0, sizeof(AddressInfo));
35  function_offset = kUnknown;
36  uuid_size = 0;
37}
38
39void AddressInfo::FillModuleInfo(const char *mod_name, uptr mod_offset,
40                                 ModuleArch mod_arch) {
41  module = internal_strdup(mod_name);
42  module_offset = mod_offset;
43  module_arch = mod_arch;
44  uuid_size = 0;
45}
46
47void AddressInfo::FillModuleInfo(const LoadedModule &mod) {
48  module = internal_strdup(mod.full_name());
49  module_offset = address - mod.base_address();
50  module_arch = mod.arch();
51  if (mod.uuid_size())
52    internal_memcpy(uuid, mod.uuid(), mod.uuid_size());
53  uuid_size = mod.uuid_size();
54}
55
56SymbolizedStack::SymbolizedStack() : next(nullptr), info() {}
57
58SymbolizedStack *SymbolizedStack::New(uptr addr) {
59  void *mem = InternalAlloc(sizeof(SymbolizedStack));
60  SymbolizedStack *res = new(mem) SymbolizedStack();
61  res->info.address = addr;
62  return res;
63}
64
65void SymbolizedStack::ClearAll() {
66  info.Clear();
67  if (next)
68    next->ClearAll();
69  InternalFree(this);
70}
71
72DataInfo::DataInfo() {
73  internal_memset(this, 0, sizeof(DataInfo));
74}
75
76void DataInfo::Clear() {
77  InternalFree(module);
78  InternalFree(file);
79  InternalFree(name);
80  internal_memset(this, 0, sizeof(DataInfo));
81}
82
83void FrameInfo::Clear() {
84  InternalFree(module);
85  for (LocalInfo &local : locals) {
86    InternalFree(local.function_name);
87    InternalFree(local.name);
88    InternalFree(local.decl_file);
89  }
90  locals.clear();
91}
92
93Symbolizer *Symbolizer::symbolizer_;
94StaticSpinMutex Symbolizer::init_mu_;
95LowLevelAllocator Symbolizer::symbolizer_allocator_;
96
97void Symbolizer::InvalidateModuleList() {
98  modules_fresh_ = false;
99}
100
101void Symbolizer::AddHooks(Symbolizer::StartSymbolizationHook start_hook,
102                          Symbolizer::EndSymbolizationHook end_hook) {
103  CHECK(start_hook_ == 0 && end_hook_ == 0);
104  start_hook_ = start_hook;
105  end_hook_ = end_hook;
106}
107
108const char *Symbolizer::ModuleNameOwner::GetOwnedCopy(const char *str) {
109  mu_->CheckLocked();
110
111  // 'str' will be the same string multiple times in a row, optimize this case.
112  if (last_match_ && !internal_strcmp(last_match_, str))
113    return last_match_;
114
115  // FIXME: this is linear search.
116  // We should optimize this further if this turns out to be a bottleneck later.
117  for (uptr i = 0; i < storage_.size(); ++i) {
118    if (!internal_strcmp(storage_[i], str)) {
119      last_match_ = storage_[i];
120      return last_match_;
121    }
122  }
123  last_match_ = internal_strdup(str);
124  storage_.push_back(last_match_);
125  return last_match_;
126}
127
128Symbolizer::Symbolizer(IntrusiveList<SymbolizerTool> tools)
129    : module_names_(&mu_), modules_(), modules_fresh_(false), tools_(tools),
130      start_hook_(0), end_hook_(0) {}
131
132Symbolizer::SymbolizerScope::SymbolizerScope(const Symbolizer *sym)
133    : sym_(sym), errno_(errno) {
134  if (sym_->start_hook_)
135    sym_->start_hook_();
136}
137
138Symbolizer::SymbolizerScope::~SymbolizerScope() {
139  if (sym_->end_hook_)
140    sym_->end_hook_();
141  errno = errno_;
142}
143
144}  // namespace __sanitizer
145