Coverage Report

Created: 2025-06-13 06:34

/src/perfetto/buildtools/android-unwinding/libunwindstack/GlobalDebugImpl.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2017 The Android Open Source Project
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
#pragma once
18
19
#include <stdint.h>
20
#include <string.h>
21
#include <sys/mman.h>
22
23
#include <memory>
24
#include <vector>
25
26
#include <unwindstack/Global.h>
27
#include <unwindstack/Maps.h>
28
29
#include "Check.h"
30
#include "GlobalDebugInterface.h"
31
#include "MemoryCache.h"
32
#include "MemoryRange.h"
33
34
// This implements the JIT Compilation Interface.
35
// See https://sourceware.org/gdb/onlinedocs/gdb/JIT-Interface.html
36
//
37
// We use it to get in-memory ELF files created by the ART compiler,
38
// but we also use it to get list of DEX files used by the runtime.
39
40
namespace unwindstack {
41
42
// Implementation templated for ELF/DEX and for different architectures.
43
template <typename Symfile, typename Uintptr_T, typename Uint64_T>
44
class GlobalDebugImpl : public GlobalDebugInterface<Symfile>, public Global {
45
 public:
46
  static constexpr int kMaxRaceRetries = 16;
47
  static constexpr int kMaxHeadRetries = 16;
48
  static constexpr uint8_t kMagic[8] = {'A', 'n', 'd', 'r', 'o', 'i', 'd', '2'};
49
50
  struct JITCodeEntry {
51
    Uintptr_T next;
52
    Uintptr_T prev;
53
    Uintptr_T symfile_addr;
54
    Uint64_T symfile_size;
55
    // Android-specific fields:
56
    Uint64_T timestamp;
57
    uint32_t seqlock;
58
  };
59
60
  static constexpr size_t kSizeOfCodeEntryV1 = offsetof(JITCodeEntry, timestamp);
61
  static constexpr size_t kSizeOfCodeEntryV2 = sizeof(JITCodeEntry);
62
63
  struct JITDescriptor {
64
    uint32_t version;
65
    uint32_t action_flag;
66
    Uintptr_T relevant_entry;
67
    Uintptr_T first_entry;
68
    // Android-specific fields:
69
    uint8_t magic[8];
70
    uint32_t flags;
71
    uint32_t sizeof_descriptor;
72
    uint32_t sizeof_entry;
73
    uint32_t seqlock;
74
    Uint64_T timestamp;
75
  };
76
77
  static constexpr size_t kSizeOfDescriptorV1 = offsetof(JITDescriptor, magic);
78
  static constexpr size_t kSizeOfDescriptorV2 = sizeof(JITDescriptor);
79
80
  // This uniquely identifies entry in presence of concurrent modifications.
81
  // Each (address,seqlock) pair is unique for each newly created JIT entry.
82
  struct UID {
83
    uint64_t address;  // Address of JITCodeEntry in memory.
84
    uint32_t seqlock;  // This servers as "version" for the given address.
85
86
0
    bool operator<(const UID& other) const {
87
0
      return std::tie(address, seqlock) < std::tie(other.address, other.seqlock);
88
0
    }
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::UID::operator<(unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::UID const&) const
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::UID::operator<(unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::UID const&) const
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::UID::operator<(unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::UID const&) const
89
  };
90
91
  GlobalDebugImpl(ArchEnum arch, std::shared_ptr<Memory>& memory,
92
                  std::vector<std::string>& search_libs, const char* global_variable_name)
93
0
      : Global(memory, search_libs), global_variable_name_(global_variable_name) {
94
0
    SetArch(arch);
95
0
  }
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::GlobalDebugImpl(unwindstack::ArchEnum, std::__1::shared_ptr<unwindstack::Memory>&, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&, char const*)
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::GlobalDebugImpl(unwindstack::ArchEnum, std::__1::shared_ptr<unwindstack::Memory>&, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&, char const*)
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::GlobalDebugImpl(unwindstack::ArchEnum, std::__1::shared_ptr<unwindstack::Memory>&, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&, char const*)
96
97
0
  bool ReadDescriptor(uint64_t addr) {
98
0
    JITDescriptor desc{};
99
    // Try to read the full descriptor including Android-specific fields.
100
0
    if (!this->memory_->ReadFully(addr, &desc, kSizeOfDescriptorV2)) {
101
      // Fallback to just the minimal descriptor.
102
      // This will make the magic check below fail.
103
0
      if (!this->memory_->ReadFully(addr, &desc, kSizeOfDescriptorV1)) {
104
0
        return false;
105
0
      }
106
0
    }
107
108
0
    if (desc.version != 1 || desc.first_entry == 0) {
109
      // Either unknown version, or no jit entries.
110
0
      return false;
111
0
    }
112
113
    // Check if there are extra Android-specific fields.
114
0
    if (memcmp(desc.magic, kMagic, sizeof(kMagic)) == 0) {
115
0
      jit_entry_size_ = kSizeOfCodeEntryV2;
116
0
      seqlock_offset_ = offsetof(JITCodeEntry, seqlock);
117
0
    } else {
118
0
      jit_entry_size_ = kSizeOfCodeEntryV1;
119
0
      seqlock_offset_ = 0;
120
0
    }
121
0
    descriptor_addr_ = addr;
122
0
    return true;
123
0
  }
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::ReadDescriptor(unsigned long)
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::ReadDescriptor(unsigned long)
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::ReadDescriptor(unsigned long)
124
125
0
  void ProcessArch() {}
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::ProcessArch()
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::ProcessArch()
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::ProcessArch()
126
127
0
  bool ReadVariableData(uint64_t ptr) { return ReadDescriptor(ptr); }
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::ReadVariableData(unsigned long)
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::ReadVariableData(unsigned long)
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::ReadVariableData(unsigned long)
128
129
  // Invoke callback for all symfiles that contain the given PC.
130
  // Returns true if any callback returns true (which also aborts the iteration).
131
  template <typename Callback /* (Symfile*) -> bool */>
132
0
  bool ForEachSymfile(Maps* maps, uint64_t pc, Callback callback) {
133
    // Use a single lock, this object should be used so infrequently that
134
    // a fine grain lock is unnecessary.
135
0
    std::lock_guard<std::mutex> guard(lock_);
136
0
    if (descriptor_addr_ == 0) {
137
0
      FindAndReadVariable(maps, global_variable_name_);
138
0
      if (descriptor_addr_ == 0) {
139
0
        return false;
140
0
      }
141
0
    }
142
143
    // Try to find the entry in already loaded symbol files.
144
0
    for (auto& it : entries_) {
145
0
      Symfile* symfile = it.second.get();
146
      // Check seqlock to make sure that entry is still valid (it may be very old).
147
0
      if (symfile->IsValidPc(pc) && CheckSeqlock(it.first) && callback(symfile)) {
148
0
        return true;
149
0
      }
150
0
    }
151
152
    // Update all entries and retry.
153
0
    ReadAllEntries(maps);
154
0
    for (auto& it : entries_) {
155
0
      Symfile* symfile = it.second.get();
156
      // Note that the entry could become invalid since the ReadAllEntries above,
157
      // but that is ok.  We don't want to fail or refresh the entries yet again.
158
      // This is as if we found the entry in time and it became invalid after return.
159
      // This is relevant when ART moves/packs JIT entries. That is, the entry is
160
      // technically deleted, but only because it was copied into merged uber-entry.
161
      // So the JIT method is still alive and the deleted data is still correct.
162
0
      if (symfile->IsValidPc(pc) && callback(symfile)) {
163
0
        return true;
164
0
      }
165
0
    }
166
167
0
    return false;
168
0
  }
Unexecuted instantiation: bool unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::ForEachSymfile<unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::GetFunctionName(unwindstack::Maps*, unsigned long, unwindstack::SharedString*, unsigned long*)::{lambda(unwindstack::Elf*)#1}>(unwindstack::Maps*, unsigned long, unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::GetFunctionName(unwindstack::Maps*, unsigned long, unwindstack::SharedString*, unsigned long*)::{lambda(unwindstack::Elf*)#1})
Unexecuted instantiation: bool unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::ForEachSymfile<unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::Find(unwindstack::Maps*, unsigned long)::{lambda(unwindstack::Elf*)#1}>(unwindstack::Maps*, unsigned long, unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::Find(unwindstack::Maps*, unsigned long)::{lambda(unwindstack::Elf*)#1})
Unexecuted instantiation: bool unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::ForEachSymfile<unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::GetFunctionName(unwindstack::Maps*, unsigned long, unwindstack::SharedString*, unsigned long*)::{lambda(unwindstack::Elf*)#1}>(unwindstack::Maps*, unsigned long, unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::GetFunctionName(unwindstack::Maps*, unsigned long, unwindstack::SharedString*, unsigned long*)::{lambda(unwindstack::Elf*)#1})
Unexecuted instantiation: bool unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::ForEachSymfile<unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::Find(unwindstack::Maps*, unsigned long)::{lambda(unwindstack::Elf*)#1}>(unwindstack::Maps*, unsigned long, unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::Find(unwindstack::Maps*, unsigned long)::{lambda(unwindstack::Elf*)#1})
Unexecuted instantiation: bool unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::ForEachSymfile<unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::GetFunctionName(unwindstack::Maps*, unsigned long, unwindstack::SharedString*, unsigned long*)::{lambda(unwindstack::Elf*)#1}>(unwindstack::Maps*, unsigned long, unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::GetFunctionName(unwindstack::Maps*, unsigned long, unwindstack::SharedString*, unsigned long*)::{lambda(unwindstack::Elf*)#1})
Unexecuted instantiation: bool unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::ForEachSymfile<unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::Find(unwindstack::Maps*, unsigned long)::{lambda(unwindstack::Elf*)#1}>(unwindstack::Maps*, unsigned long, unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::Find(unwindstack::Maps*, unsigned long)::{lambda(unwindstack::Elf*)#1})
169
170
0
  bool GetFunctionName(Maps* maps, uint64_t pc, SharedString* name, uint64_t* offset) {
171
    // NB: If symfiles overlap in PC ranges, this will check all of them.
172
0
    return ForEachSymfile(maps, pc, [pc, name, offset](Symfile* file) {
173
0
      return file->GetFunctionName(pc, name, offset);
174
0
    });
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::GetFunctionName(unwindstack::Maps*, unsigned long, unwindstack::SharedString*, unsigned long*)::{lambda(unwindstack::Elf*)#1}::operator()(unwindstack::Elf*) const
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::GetFunctionName(unwindstack::Maps*, unsigned long, unwindstack::SharedString*, unsigned long*)::{lambda(unwindstack::Elf*)#1}::operator()(unwindstack::Elf*) const
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::GetFunctionName(unwindstack::Maps*, unsigned long, unwindstack::SharedString*, unsigned long*)::{lambda(unwindstack::Elf*)#1}::operator()(unwindstack::Elf*) const
175
0
  }
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::GetFunctionName(unwindstack::Maps*, unsigned long, unwindstack::SharedString*, unsigned long*)
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::GetFunctionName(unwindstack::Maps*, unsigned long, unwindstack::SharedString*, unsigned long*)
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::GetFunctionName(unwindstack::Maps*, unsigned long, unwindstack::SharedString*, unsigned long*)
176
177
0
  Symfile* Find(Maps* maps, uint64_t pc) {
178
    // NB: If symfiles overlap in PC ranges (which can happen for both ELF and DEX),
179
    // this will check all of them and return one that also has a matching function.
180
0
    Symfile* result = nullptr;
181
0
    bool found = ForEachSymfile(maps, pc, [pc, &result](Symfile* file) {
182
0
      result = file;
183
0
      SharedString name;
184
0
      uint64_t offset;
185
0
      return file->GetFunctionName(pc, &name, &offset);
186
0
    });
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::Find(unwindstack::Maps*, unsigned long)::{lambda(unwindstack::Elf*)#1}::operator()(unwindstack::Elf*) const
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::Find(unwindstack::Maps*, unsigned long)::{lambda(unwindstack::Elf*)#1}::operator()(unwindstack::Elf*) const
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::Find(unwindstack::Maps*, unsigned long)::{lambda(unwindstack::Elf*)#1}::operator()(unwindstack::Elf*) const
187
0
    if (found) {
188
0
      return result;  // Found symfile with symbol that also matches the PC.
189
0
    }
190
    // There is no matching symbol, so return any symfile for which the PC is valid.
191
    // This is a useful fallback for tests, which often have symfiles with no functions.
192
0
    return result;
193
0
  }
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::Find(unwindstack::Maps*, unsigned long)
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::Find(unwindstack::Maps*, unsigned long)
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::Find(unwindstack::Maps*, unsigned long)
194
195
  // Read all entries from the process and cache them locally.
196
  // The linked list might be concurrently modified. We detect races and retry.
197
0
  bool ReadAllEntries(Maps* maps) {
198
0
    for (int i = 0; i < kMaxRaceRetries; i++) {
199
0
      bool race = false;
200
0
      if (!ReadAllEntries(maps, &race)) {
201
0
        if (race) {
202
0
          continue;  // Retry due to concurrent modification of the linked list.
203
0
        }
204
0
        return false;  // Failed to read entries.
205
0
      }
206
0
      return true;  // Success.
207
0
    }
208
0
    return false;  // Too many retries.
209
0
  }
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::ReadAllEntries(unwindstack::Maps*)
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::ReadAllEntries(unwindstack::Maps*)
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::ReadAllEntries(unwindstack::Maps*)
210
211
  // Read all JIT entries while assuming there might be concurrent modifications.
212
  // If there is a race, the method will fail and the caller should retry the call.
213
0
  bool ReadAllEntries(Maps* maps, bool* race) {
214
    // New entries might be added while we iterate over the linked list.
215
    // In particular, an entry could be effectively moved from end to start due to
216
    // the ART repacking algorithm, which groups smaller entries into a big one.
217
    // Therefore keep reading the most recent entries until we reach a fixed point.
218
0
    std::map<UID, std::shared_ptr<Symfile>> entries;
219
0
    for (size_t i = 0; i < kMaxHeadRetries; i++) {
220
0
      size_t old_size = entries.size();
221
0
      if (!ReadNewEntries(maps, &entries, race)) {
222
0
        return false;
223
0
      }
224
0
      if (entries.size() == old_size) {
225
0
        entries_.swap(entries);
226
0
        return true;
227
0
      }
228
0
    }
229
0
    return false;  // Too many retries.
230
0
  }
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::ReadAllEntries(unwindstack::Maps*, bool*)
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::ReadAllEntries(unwindstack::Maps*, bool*)
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::ReadAllEntries(unwindstack::Maps*, bool*)
231
232
  // Read new JIT entries (head of linked list) until we find one that we have seen before.
233
  // This method uses seqlocks extensively to ensure safety in case of concurrent modifications.
234
0
  bool ReadNewEntries(Maps* maps, std::map<UID, std::shared_ptr<Symfile>>* entries, bool* race) {
235
    // Read the address of the head entry in the linked list.
236
0
    UID uid;
237
0
    if (!ReadNextField(descriptor_addr_ + offsetof(JITDescriptor, first_entry), &uid, race)) {
238
0
      return false;
239
0
    }
240
241
    // Follow the linked list.
242
0
    while (uid.address != 0) {
243
      // Check if we have reached an already cached entry (we restart from head repeatedly).
244
0
      if (entries->count(uid) != 0) {
245
0
        return true;
246
0
      }
247
248
      // Read the entry.
249
0
      JITCodeEntry data{};
250
0
      if (!memory_->ReadFully(uid.address, &data, jit_entry_size_)) {
251
0
        return false;
252
0
      }
253
0
      data.symfile_addr = StripAddressTag(data.symfile_addr);
254
255
      // Check the seqlock to verify the symfile_addr and symfile_size.
256
0
      if (!CheckSeqlock(uid, race)) {
257
0
        return false;
258
0
      }
259
260
      // Copy and load the symfile.
261
0
      auto it = entries_.find(uid);
262
0
      if (it != entries_.end()) {
263
        // The symfile was already loaded - just copy the reference.
264
0
        entries->emplace(uid, it->second);
265
0
      } else if (data.symfile_addr != 0) {
266
0
        std::shared_ptr<Symfile> symfile;
267
0
        bool ok = this->Load(maps, memory_, data.symfile_addr, data.symfile_size.value, symfile);
268
        // Check seqlock first because load can fail due to race (so we want to trigger retry).
269
        // TODO: Extract the memory copy code before the load, so that it is immune to races.
270
0
        if (!CheckSeqlock(uid, race)) {
271
0
          return false;  // The ELF/DEX data was removed before we loaded it.
272
0
        }
273
        // Exclude symbol files that fail to load (but continue loading other files).
274
0
        if (ok) {
275
0
          entries->emplace(uid, symfile);
276
0
        }
277
0
      }
278
279
      // Go to next entry.
280
0
      UID next_uid;
281
0
      if (!ReadNextField(uid.address + offsetof(JITCodeEntry, next), &next_uid, race)) {
282
0
        return false;  // The next pointer was modified while we were reading it.
283
0
      }
284
0
      if (!CheckSeqlock(uid, race)) {
285
0
        return false;  // This entry was deleted before we moved to the next one.
286
0
      }
287
0
      uid = next_uid;
288
0
    }
289
290
0
    return true;
291
0
  }
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::ReadNewEntries(unwindstack::Maps*, std::__1::map<unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::UID, std::__1::shared_ptr<unwindstack::Elf>, std::__1::less<unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::UID>, std::__1::allocator<std::__1::pair<unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::UID const, std::__1::shared_ptr<unwindstack::Elf> > > >*, bool*)
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::ReadNewEntries(unwindstack::Maps*, std::__1::map<unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::UID, std::__1::shared_ptr<unwindstack::Elf>, std::__1::less<unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::UID>, std::__1::allocator<std::__1::pair<unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::UID const, std::__1::shared_ptr<unwindstack::Elf> > > >*, bool*)
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::ReadNewEntries(unwindstack::Maps*, std::__1::map<unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::UID, std::__1::shared_ptr<unwindstack::Elf>, std::__1::less<unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::UID>, std::__1::allocator<std::__1::pair<unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::UID const, std::__1::shared_ptr<unwindstack::Elf> > > >*, bool*)
292
293
  // Read the address and seqlock of entry from the next field of linked list.
294
  // This is non-trivial since they need to be consistent (as if we read both atomically).
295
  //
296
  // We're reading pointers, which can point at heap-allocated structures (the
297
  // case for the __dex_debug_descriptor pointers at the time of writing).
298
  // On 64 bit systems, the target process might have top-byte heap pointer
299
  // tagging enabled, so we need to mask out the tag. We also know that the
300
  // address must point to userspace, so the top byte of the address must be
301
  // zero on both x64 and aarch64 without tagging. Therefore the masking can be
302
  // done unconditionally.
303
0
  bool ReadNextField(uint64_t next_field_addr, UID* uid, bool* race) {
304
0
    Uintptr_T address[2]{0, 0};
305
0
    uint32_t seqlock[2]{0, 0};
306
    // Read all data twice: address[0], seqlock[0], address[1], seqlock[1].
307
0
    for (int i = 0; i < 2; i++) {
308
0
      std::atomic_thread_fence(std::memory_order_acquire);
309
0
      if (!(memory_->ReadFully(next_field_addr, &address[i], sizeof(address[i])))) {
310
0
        return false;
311
0
      }
312
0
      address[i] = StripAddressTag(address[i]);
313
0
      if (seqlock_offset_ == 0) {
314
        // There is no seqlock field.
315
0
        *uid = UID{.address = address[0], .seqlock = 0};
316
0
        return true;
317
0
      }
318
0
      if (address[i] != 0) {
319
0
        std::atomic_thread_fence(std::memory_order_acquire);
320
0
        if (!memory_->ReadFully(address[i] + seqlock_offset_, &seqlock[i], sizeof(seqlock[i]))) {
321
0
          return false;
322
0
        }
323
0
      }
324
0
    }
325
    // Check that both reads returned identical values, and that the entry is live.
326
0
    if (address[0] != address[1] || seqlock[0] != seqlock[1] || (seqlock[0] & 1) == 1) {
327
0
      *race = true;
328
0
      return false;
329
0
    }
330
    // Since address[1] is sandwiched between two seqlock reads, we know that
331
    // at the time of address[1] read, the entry had the given seqlock value.
332
0
    *uid = UID{.address = address[1], .seqlock = seqlock[1]};
333
0
    return true;
334
0
  }
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::ReadNextField(unsigned long, unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::UID*, bool*)
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::ReadNextField(unsigned long, unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::UID*, bool*)
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::ReadNextField(unsigned long, unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::UID*, bool*)
335
336
  // Check that the given entry has not been deleted (or replaced by new entry at same address).
337
0
  bool CheckSeqlock(UID uid, bool* race = nullptr) {
338
0
    if (seqlock_offset_ == 0) {
339
      // There is no seqlock field.
340
0
      return true;
341
0
    }
342
    // This is required for memory synchronization if the we are working with local memory.
343
    // For other types of memory (e.g. remote) this is no-op and has no significant effect.
344
0
    std::atomic_thread_fence(std::memory_order_acquire);
345
0
    uint32_t seen_seqlock;
346
0
    if (!memory_->Read32(uid.address + seqlock_offset_, &seen_seqlock)) {
347
0
      return false;
348
0
    }
349
0
    if (seen_seqlock != uid.seqlock) {
350
0
      if (race != nullptr) {
351
0
        *race = true;
352
0
      }
353
0
      return false;
354
0
    }
355
0
    return true;
356
0
  }
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::CheckSeqlock(unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::UID, bool*)
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::CheckSeqlock(unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::UID, bool*)
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::CheckSeqlock(unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::UID, bool*)
357
358
  // AArch64 has Address tagging (aka Top Byte Ignore) feature, which is used by
359
  // HWASAN and MTE to store metadata in the address. We need to remove the tag.
360
0
  Uintptr_T StripAddressTag(Uintptr_T addr) {
361
0
    if (arch() == ARCH_ARM64) {
362
      // Make the value signed so it will be sign extended if necessary.
363
0
      return static_cast<Uintptr_T>((static_cast<int64_t>(addr) << 8) >> 8);
364
0
    }
365
0
    return addr;
366
0
  }
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_P>::StripAddressTag(unsigned int)
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned int, unwindstack::Uint64_A>::StripAddressTag(unsigned int)
Unexecuted instantiation: unwindstack::GlobalDebugImpl<unwindstack::Elf, unsigned long, unwindstack::Uint64_A>::StripAddressTag(unsigned long)
367
368
 private:
369
  const char* global_variable_name_ = nullptr;
370
  uint64_t descriptor_addr_ = 0;  // Non-zero if we have found (non-empty) descriptor.
371
  uint32_t jit_entry_size_ = 0;
372
  uint32_t seqlock_offset_ = 0;
373
  std::map<UID, std::shared_ptr<Symfile>> entries_;  // Cached loaded entries.
374
375
  std::mutex lock_;
376
};
377
378
// uint64_t values on x86 are not naturally aligned,
379
// but uint64_t values on ARM are naturally aligned.
380
struct Uint64_P {
381
  uint64_t value;
382
} __attribute__((packed));
383
struct Uint64_A {
384
  uint64_t value;
385
} __attribute__((aligned(8)));
386
387
template <typename Symfile>
388
std::unique_ptr<GlobalDebugInterface<Symfile>> CreateGlobalDebugImpl(
389
    ArchEnum arch, std::shared_ptr<Memory>& memory, std::vector<std::string> search_libs,
390
0
    const char* global_variable_name) {
391
0
  CHECK(arch != ARCH_UNKNOWN);
392
393
  // The interface needs to see real-time changes in memory for synchronization with the
394
  // concurrently running ART JIT compiler. Skip caching and read the memory directly.
395
0
  std::shared_ptr<Memory> jit_memory;
396
0
  MemoryCacheBase* cached_memory = memory->AsMemoryCacheBase();
397
0
  if (cached_memory != nullptr) {
398
0
    jit_memory = cached_memory->UnderlyingMemory();
399
0
  } else {
400
0
    jit_memory = memory;
401
0
  }
402
403
0
  switch (arch) {
404
0
    case ARCH_X86: {
405
0
      using Impl = GlobalDebugImpl<Symfile, uint32_t, Uint64_P>;
406
0
      static_assert(offsetof(typename Impl::JITCodeEntry, symfile_size) == 12, "layout");
407
0
      static_assert(offsetof(typename Impl::JITCodeEntry, seqlock) == 28, "layout");
408
0
      static_assert(sizeof(typename Impl::JITCodeEntry) == 32, "layout");
409
0
      static_assert(sizeof(typename Impl::JITDescriptor) == 48, "layout");
410
0
      return std::make_unique<Impl>(arch, jit_memory, search_libs, global_variable_name);
411
0
    }
412
0
    case ARCH_ARM: {
413
0
      using Impl = GlobalDebugImpl<Symfile, uint32_t, Uint64_A>;
414
0
      static_assert(offsetof(typename Impl::JITCodeEntry, symfile_size) == 16, "layout");
415
0
      static_assert(offsetof(typename Impl::JITCodeEntry, seqlock) == 32, "layout");
416
0
      static_assert(sizeof(typename Impl::JITCodeEntry) == 40, "layout");
417
0
      static_assert(sizeof(typename Impl::JITDescriptor) == 48, "layout");
418
0
      return std::make_unique<Impl>(arch, jit_memory, search_libs, global_variable_name);
419
0
    }
420
0
    case ARCH_ARM64:
421
0
    case ARCH_X86_64:
422
0
    case ARCH_RISCV64: {
423
0
      using Impl = GlobalDebugImpl<Symfile, uint64_t, Uint64_A>;
424
0
      static_assert(offsetof(typename Impl::JITCodeEntry, symfile_size) == 24, "layout");
425
0
      static_assert(offsetof(typename Impl::JITCodeEntry, seqlock) == 40, "layout");
426
0
      static_assert(sizeof(typename Impl::JITCodeEntry) == 48, "layout");
427
0
      static_assert(sizeof(typename Impl::JITDescriptor) == 56, "layout");
428
0
      return std::make_unique<Impl>(arch, jit_memory, search_libs, global_variable_name);
429
0
    }
430
0
    default:
431
0
      abort();
432
0
  }
433
0
}
434
435
}  // namespace unwindstack