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 <stdint.h>
18
19#include <functional>
20
21#include <unwindstack/Elf.h>
22#include <unwindstack/MachineArm.h>
23#include <unwindstack/MapInfo.h>
24#include <unwindstack/Memory.h>
25#include <unwindstack/RegsArm.h>
26#include <unwindstack/UcontextArm.h>
27#include <unwindstack/UserArm.h>
28
29namespace unwindstack {
30
31RegsArm::RegsArm() : RegsImpl<uint32_t>(ARM_REG_LAST, Location(LOCATION_REGISTER, ARM_REG_LR)) {}
32
33ArchEnum RegsArm::Arch() {
34  return ARCH_ARM;
35}
36
37uint64_t RegsArm::pc() {
38  return regs_[ARM_REG_PC];
39}
40
41uint64_t RegsArm::sp() {
42  return regs_[ARM_REG_SP];
43}
44
45void RegsArm::set_pc(uint64_t pc) {
46  regs_[ARM_REG_PC] = pc;
47}
48
49void RegsArm::set_sp(uint64_t sp) {
50  regs_[ARM_REG_SP] = sp;
51}
52
53uint64_t RegsArm::GetPcAdjustment(uint64_t rel_pc, Elf* elf) {
54  if (!elf->valid()) {
55    return 2;
56  }
57
58  uint64_t load_bias = elf->GetLoadBias();
59  if (rel_pc < load_bias) {
60    if (rel_pc < 2) {
61      return 0;
62    }
63    return 2;
64  }
65  uint64_t adjusted_rel_pc = rel_pc - load_bias;
66  if (adjusted_rel_pc < 5) {
67    if (adjusted_rel_pc < 2) {
68      return 0;
69    }
70    return 2;
71  }
72
73  if (adjusted_rel_pc & 1) {
74    // This is a thumb instruction, it could be 2 or 4 bytes.
75    uint32_t value;
76    if (!elf->memory()->ReadFully(adjusted_rel_pc - 5, &value, sizeof(value)) ||
77        (value & 0xe000f000) != 0xe000f000) {
78      return 2;
79    }
80  }
81  return 4;
82}
83
84bool RegsArm::SetPcFromReturnAddress(Memory*) {
85  uint32_t lr = regs_[ARM_REG_LR];
86  if (regs_[ARM_REG_PC] == lr) {
87    return false;
88  }
89
90  regs_[ARM_REG_PC] = lr;
91  return true;
92}
93
94void RegsArm::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
95  fn("r0", regs_[ARM_REG_R0]);
96  fn("r1", regs_[ARM_REG_R1]);
97  fn("r2", regs_[ARM_REG_R2]);
98  fn("r3", regs_[ARM_REG_R3]);
99  fn("r4", regs_[ARM_REG_R4]);
100  fn("r5", regs_[ARM_REG_R5]);
101  fn("r6", regs_[ARM_REG_R6]);
102  fn("r7", regs_[ARM_REG_R7]);
103  fn("r8", regs_[ARM_REG_R8]);
104  fn("r9", regs_[ARM_REG_R9]);
105  fn("r10", regs_[ARM_REG_R10]);
106  fn("r11", regs_[ARM_REG_R11]);
107  fn("ip", regs_[ARM_REG_R12]);
108  fn("sp", regs_[ARM_REG_SP]);
109  fn("lr", regs_[ARM_REG_LR]);
110  fn("pc", regs_[ARM_REG_PC]);
111}
112
113Regs* RegsArm::Read(void* remote_data) {
114  arm_user_regs* user = reinterpret_cast<arm_user_regs*>(remote_data);
115
116  RegsArm* regs = new RegsArm();
117  memcpy(regs->RawData(), &user->regs[0], ARM_REG_LAST * sizeof(uint32_t));
118  return regs;
119}
120
121Regs* RegsArm::CreateFromUcontext(void* ucontext) {
122  arm_ucontext_t* arm_ucontext = reinterpret_cast<arm_ucontext_t*>(ucontext);
123
124  RegsArm* regs = new RegsArm();
125  memcpy(regs->RawData(), &arm_ucontext->uc_mcontext.regs[0], ARM_REG_LAST * sizeof(uint32_t));
126  return regs;
127}
128
129bool RegsArm::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
130  uint32_t data;
131  Memory* elf_memory = elf->memory();
132  // Read from elf memory since it is usually more expensive to read from
133  // process memory.
134  if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) {
135    return false;
136  }
137
138  uint64_t offset = 0;
139  if (data == 0xe3a07077 || data == 0xef900077 || data == 0xdf002777) {
140    uint64_t sp = regs_[ARM_REG_SP];
141    // non-RT sigreturn call.
142    // __restore:
143    //
144    // Form 1 (arm):
145    // 0x77 0x70              mov r7, #0x77
146    // 0xa0 0xe3              svc 0x00000000
147    //
148    // Form 2 (arm):
149    // 0x77 0x00 0x90 0xef    svc 0x00900077
150    //
151    // Form 3 (thumb):
152    // 0x77 0x27              movs r7, #77
153    // 0x00 0xdf              svc 0
154    if (!process_memory->ReadFully(sp, &data, sizeof(data))) {
155      return false;
156    }
157    if (data == 0x5ac3c35a) {
158      // SP + uc_mcontext offset + r0 offset.
159      offset = sp + 0x14 + 0xc;
160    } else {
161      // SP + r0 offset
162      offset = sp + 0xc;
163    }
164  } else if (data == 0xe3a070ad || data == 0xef9000ad || data == 0xdf0027ad) {
165    uint64_t sp = regs_[ARM_REG_SP];
166    // RT sigreturn call.
167    // __restore_rt:
168    //
169    // Form 1 (arm):
170    // 0xad 0x70      mov r7, #0xad
171    // 0xa0 0xe3      svc 0x00000000
172    //
173    // Form 2 (arm):
174    // 0xad 0x00 0x90 0xef    svc 0x009000ad
175    //
176    // Form 3 (thumb):
177    // 0xad 0x27              movs r7, #ad
178    // 0x00 0xdf              svc 0
179    if (!process_memory->ReadFully(sp, &data, sizeof(data))) {
180      return false;
181    }
182    if (data == sp + 8) {
183      // SP + 8 + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
184      offset = sp + 8 + 0x80 + 0x14 + 0xc;
185    } else {
186      // SP + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
187      offset = sp + 0x80 + 0x14 + 0xc;
188    }
189  }
190  if (offset == 0) {
191    return false;
192  }
193
194  if (!process_memory->ReadFully(offset, regs_.data(), sizeof(uint32_t) * ARM_REG_LAST)) {
195    return false;
196  }
197  return true;
198}
199
200Regs* RegsArm::Clone() {
201  return new RegsArm(*this);
202}
203
204}  // namespace unwindstack
205