Coverage Report

Created: 2026-10-28 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/perfetto/buildtools/android-unwinding/libunwindstack/Regs.cpp
Line
Count
Source
1
/*
2
 * Copyright (C) 2016 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
#include <errno.h>
18
#include <stdint.h>
19
#include <string.h>
20
#include <sys/ptrace.h>
21
#include <sys/uio.h>
22
23
#include <algorithm>
24
#include <vector>
25
26
#include <unwindstack/Elf.h>
27
#include <unwindstack/Log.h>
28
#include <unwindstack/MapInfo.h>
29
#include <unwindstack/Regs.h>
30
#include <unwindstack/RegsArm.h>
31
#include <unwindstack/RegsArm64.h>
32
#include <unwindstack/RegsRiscv64.h>
33
#include <unwindstack/RegsX86.h>
34
#include <unwindstack/RegsX86_64.h>
35
#include <unwindstack/UserArm.h>
36
#include <unwindstack/UserArm64.h>
37
#include <unwindstack/UserRiscv64.h>
38
#include <unwindstack/UserX86.h>
39
#include <unwindstack/UserX86_64.h>
40
41
namespace unwindstack {
42
43
// The largest user structure.
44
// constexpr size_t MAX_USER_REGS_SIZE = sizeof(mips64_user_regs) + 10;
45
static constexpr size_t kMaxUserRegsSize = std::max(
46
    sizeof(arm_user_regs),
47
    std::max(sizeof(arm64_user_regs), std::max(sizeof(x86_user_regs), sizeof(x86_64_user_regs))));
48
49
// This function assumes that reg_data is already aligned to a 64 bit value.
50
// If not this could crash with an unaligned access.
51
0
Regs* Regs::RemoteGet(pid_t pid, ErrorCode* error_code) {
52
  // Make the buffer large enough to contain the largest registers type.
53
0
  std::vector<uint64_t> buffer(kMaxUserRegsSize / sizeof(uint64_t));
54
0
  struct iovec io {
55
0
    .iov_base = buffer.data(), .iov_len = buffer.size() * sizeof(uint64_t)
56
0
  };
57
58
0
  if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, reinterpret_cast<void*>(&io)) == -1) {
59
0
    Log::Error("PTRACE_GETREGSET failed for pid %d: %s", pid, strerror(errno));
60
0
    if (error_code != nullptr) {
61
0
      *error_code = ERROR_PTRACE_CALL;
62
0
    }
63
0
    return nullptr;
64
0
  }
65
66
  // Infer the process architecture from the size of its register structure.
67
0
  switch (io.iov_len) {
68
0
  case sizeof(x86_user_regs):
69
0
    return RegsX86::Read(buffer.data());
70
0
  case sizeof(x86_64_user_regs):
71
0
    return RegsX86_64::Read(buffer.data());
72
0
  case sizeof(arm_user_regs):
73
0
    return RegsArm::Read(buffer.data());
74
0
  case sizeof(arm64_user_regs):
75
0
    return RegsArm64::Read(buffer.data());
76
0
  case sizeof(riscv64_user_regs):
77
0
    return RegsRiscv64::Read(buffer.data(), pid);
78
0
  }
79
80
0
  Log::Error("No matching size of user regs structure for pid %d: size %zu", pid, io.iov_len);
81
0
  if (error_code != nullptr) {
82
0
    *error_code = ERROR_UNSUPPORTED;
83
0
  }
84
0
  return nullptr;
85
0
}
86
87
0
ArchEnum Regs::RemoteGetArch(pid_t pid, ErrorCode* error_code) {
88
  // Make the buffer large enough to contain the largest registers type.
89
0
  std::vector<uint64_t> buffer(kMaxUserRegsSize / sizeof(uint64_t));
90
0
  struct iovec io;
91
0
  io.iov_base = buffer.data();
92
0
  io.iov_len = buffer.size() * sizeof(uint64_t);
93
94
0
  if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, reinterpret_cast<void*>(&io)) == -1) {
95
0
    Log::Error("PTRACE_GETREGSET failed for pid %d: %s", pid, strerror(errno));
96
0
    if (error_code != nullptr) {
97
0
      *error_code = ERROR_PTRACE_CALL;
98
0
    }
99
0
    return ARCH_UNKNOWN;
100
0
  }
101
102
  // Infer the process architecture from the size of its register structure.
103
0
  switch (io.iov_len) {
104
0
    case sizeof(x86_user_regs):
105
0
      return ARCH_X86;
106
0
    case sizeof(x86_64_user_regs):
107
0
      return ARCH_X86_64;
108
0
    case sizeof(arm_user_regs):
109
0
      return ARCH_ARM;
110
0
    case sizeof(arm64_user_regs):
111
0
      return ARCH_ARM64;
112
0
    case sizeof(riscv64_user_regs):
113
0
      return ARCH_RISCV64;
114
0
  }
115
116
0
  Log::Error("No matching size of user regs structure for pid %d: size %zu", pid, io.iov_len);
117
0
  if (error_code != nullptr) {
118
0
    *error_code = ERROR_UNSUPPORTED;
119
0
  }
120
0
  return ARCH_UNKNOWN;
121
0
}
122
123
0
Regs* Regs::CreateFromUcontext(ArchEnum arch, void* ucontext) {
124
0
  switch (arch) {
125
0
    case ARCH_X86:
126
0
      return RegsX86::CreateFromUcontext(ucontext);
127
0
    case ARCH_X86_64:
128
0
      return RegsX86_64::CreateFromUcontext(ucontext);
129
0
    case ARCH_ARM:
130
0
      return RegsArm::CreateFromUcontext(ucontext);
131
0
    case ARCH_ARM64:
132
0
      return RegsArm64::CreateFromUcontext(ucontext);
133
0
    case ARCH_RISCV64:
134
0
      return RegsRiscv64::CreateFromUcontext(ucontext);
135
0
    case ARCH_UNKNOWN:
136
0
    default:
137
0
      return nullptr;
138
0
  }
139
0
}
140
141
0
ArchEnum Regs::CurrentArch() {
142
#if defined(__arm__)
143
  return ARCH_ARM;
144
#elif defined(__aarch64__)
145
  return ARCH_ARM64;
146
#elif defined(__i386__)
147
  return ARCH_X86;
148
#elif defined(__x86_64__)
149
  return ARCH_X86_64;
150
#elif defined(__riscv)
151
  return ARCH_RISCV64;
152
#else
153
  abort();
154
#endif
155
0
}
156
157
0
Regs* Regs::CreateFromLocal() {
158
0
  Regs* regs;
159
#if defined(__arm__)
160
  regs = new RegsArm();
161
#elif defined(__aarch64__)
162
  regs = new RegsArm64();
163
#elif defined(__i386__)
164
  regs = new RegsX86();
165
#elif defined(__x86_64__)
166
  regs = new RegsX86_64();
167
#elif defined(__riscv)
168
  regs = new RegsRiscv64();
169
#else
170
  abort();
171
#endif
172
0
  return regs;
173
0
}
174
175
2.05k
uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf, ArchEnum arch) {
176
2.05k
  switch (arch) {
177
0
    case ARCH_ARM: {
178
0
      if (!elf->valid()) {
179
0
        return 2;
180
0
      }
181
182
0
      uint64_t load_bias = elf->GetLoadBias();
183
0
      if (rel_pc < load_bias) {
184
0
        if (rel_pc < 2) {
185
0
          return 0;
186
0
        }
187
0
        return 2;
188
0
      }
189
0
      uint64_t adjusted_rel_pc = rel_pc - load_bias;
190
0
      if (adjusted_rel_pc < 5) {
191
0
        if (adjusted_rel_pc < 2) {
192
0
          return 0;
193
0
        }
194
0
        return 2;
195
0
      }
196
197
0
      if (adjusted_rel_pc & 1) {
198
        // This is a thumb instruction, it could be 2 or 4 bytes.
199
0
        uint32_t value;
200
0
        if (!elf->memory()->ReadFully(adjusted_rel_pc - 5, &value, sizeof(value)) ||
201
0
            (value & 0xe000f000) != 0xe000f000) {
202
0
          return 2;
203
0
        }
204
0
      }
205
0
      return 4;
206
0
    }
207
2.05k
    case ARCH_ARM64:
208
2.05k
    case ARCH_RISCV64: {
209
2.05k
      if (rel_pc < 4) {
210
14
        return 0;
211
14
      }
212
2.04k
      return 4;
213
2.05k
    }
214
0
  case ARCH_X86:
215
0
  case ARCH_X86_64: {
216
0
    if (rel_pc == 0) {
217
0
      return 0;
218
0
    }
219
0
    return 1;
220
0
  }
221
0
  case ARCH_UNKNOWN:
222
0
    return 0;
223
2.05k
  }
224
2.05k
}
225
226
}  // namespace unwindstack